 Go -->


VHDL

VHDL - хобби

В детстве я часто паял. Точнее - перепаивал. Деталек было мало. Чтоб спаять новую схему, надо было распаять старую. Вновь спаянная схема обычно сразу не работала по причинам плохой пайки и ошибок в монтаже.

В институте я напаялся вволю, собирая спецпроцессоры из сотен и тысяч микросхем. Проблема оставалась та же - доводка схемы путем частых перепаек. Появившиеся встраиваемые микропроцессоры вызывали легкое чувство унижения, что какой-то там американец насильно навязывает мне свое мнение в придуманной им системе команд микропроцессора. Знакомство с реализацией языка Си вызвало ассоциацию с машиной Тьюринга, в которой вычисления выполняются за счет миллионнократного повторения одних и тех же команд.

Как только я познакомился с языком VHDL и ПЛИСами, я понял, что это как раз то, чего мне с детства не хватало. Было сделано несколько проектов, пришел опыт. Но интерес к языку всё возрастал. Интерес толкал жонглировать операторами языка при реализации разных штучек, не нужных в работе, но оригинальных в исполнении и эффектных в функционировании. VHDL и ПЛИС - это как кисти и мольберт для художника. VHDL стал моим хобби. Хорошо, когда работа - хобби, а хобби - работа.

Информация о VHDL и ПЛИС занимает достойное место в интернете. Это:

  • конференция comp.arch.fpga,
  • конференция comp.lang.vhdl,
  • конференция http://server.vhdl.org/viuf/
  • журнал VHDL Times On-Line: http://vhdl.org/vhdl_intl/vltimes/
  • журнал Programmable Logic News & Views: http://www.plnv.com/
  • http://www.vhdl-online.de
  • http://www.stefanVHDL.com
  • http://www.opencores.org
  • http://www.free-ip.com
  • http://www.aldec.com.ua
и по многим другим адресам.

Я думаю, на свете есть много любителей, вроде меня, которые получают удовлетворение от проектирования и испытания разных схем, а не только от их применения или зарплаты за их разработку. Тогда, может, для них VHDL тоже станет (или стало) хобби. Поэтому для них и многих других этой статьей на данном сайте открывается рубрика:

VHDL - хобби.

Здесь будут рассматриваться такие темы, как:

  • основы языка VHDL,
  • архитектура ПЛИС,
  • полезные примеры проектов на VHDL,
  • бесплатные вычислительные заготовки на VHDL,
  • алгоритмы и устройства для цифровой обработки сигналов под ПЛИС,
  • способы проектирования работоспособных и эффективных устройств на ПЛИС,
  • обмен опытом,
  • основы проектирования систем на кристалле,
  • новые области применения VHDL и ПЛИС,
  • что нового на рынке VHDL и ПЛИС
    и т.п.

    Все желающие приглашаются для сотрудничества.
Анатолий Сергиенко
E-mail: aser@comsys.ntu-kpi.kiev.ua


VHDL

VHDL - хобби

Изучение VHDL
Методика HALLO, WORLD

Эта методика пришла к нам из времен компьютеров – динозавров. Представьте начинающего программиста у консоли компьютера в виде телетайпа. Вводится программа, запускается на компиляцию – через нecколько минут реакция консоли – ошибки в таких-то строках. Опять вводится программа – аналогичная реакция. И так далее, пока хватит терпения программиста. Бывало, что на этой почве у программиста развивался комплекс неполноценности перед тупым компьютером.

Поэтому в большинстве учебников по языкам программирования предлагалось свою первую программу написать как самую элементарную, но требующую минимум усилий для отладки. Обычно приводился один и тот же пример: программа выдачи на консоль сообщения: " HАLLO, WORLD". А дальше предлагалось последовательно совершенствовать и усложнять эту программу добавляя операторы и заменяя одни операторы на другие.

В наше время при изложении языка VHDL в большинстве учебников также не отходят от этой методики. Правда, программ выдачи на консоль этого сообщения не приводится. Тем не менее, сперва предлагается, как начать программировать логические схемы на VHDL, а затем постепенно уточняются сведения о синтаксисе, семантике и нюансы языка, которые отличают его от других алгоритмических языков.

Рассмотрим, как выглядит эта методика в чистом виде. Чтобы выдать сообщение на консоль необходимо скомпилировать и запустить на моделирование программу:

entity hаllo is --заголовок объекта проекта
end hаllo; architecture empty of hаllo is --заголовок архитектуры empty объека hаllo
begin -- начало исполнительной части архитектуры
assert 1/=1 report "Hаllo,world" ;--оператор сообщения
end hаllo; --конец архитектуры и программы

Здесь текст, начинающийся двумя тире и оканчивающийся в конце строки, означает комментарий. Оператор сообщения-ловушки assert предназначен для проверки условия моделирования и если оно ложно – значение false – выводится сообщение об ошибке. В данном случае (1/=1)= false.

Кое-что о VHDL- симуляторах.

Сейчас любая солидная САПР электроники включает в себя VHDL-симулятор. Но группа видных международных авторитетов в программировании на VHDL сходятся на том, что для обучения лучше всего подходит VHDL-симулятор Active HDL фирмы Aldec. Кроме того, что по важности не самое последнее, этот симулятор допускает коментарии, сообщения и идентификаторы на русском языке. Его бесплатную версию для обучения можно получить на сайте www.aldec.com , а литературу о нем на русском языке – на сайте www.aldec.com.ua .

Для моделирования в симуляторе Active HDL сперва нужно создать проект – каталог с файлами VHDL, имеющий название проекта. Это облегчает встроенный помощник. После компиляции в проекте создается библиотека проекта, которая имеет название проекта и содержит все скомпилированные объекты проекта. После запуска программы на моделирование сперва выполняется связывание объектов проекта и назначение начальных значений переменным и сигналам (elaboration). Затем запускается собственно симуляция. И для данной программы на консоль будет выдано сообщение:

# : ERROR : Hаllo,world
# : Time: 0 ps, Iteration: 0, TOP instance.
# KERNEL: stopped at time: 100 ns
# KERNEL: Simulation has finished. There are no more test vectors to simulate.

Программа на VHDL состоит из одного или нecкольких файлов. В одном файле размещаются одна или нecколько пар: объект проекта – архитектура объекта. Объект проекта – это интерфейсная часть, в которой указана информация о том, как включать данный объект внутри другого объекта, находящегося на более высоком уровне иерархии. А в архитектуре объекта описан алгоритм его функционирования. У одного объекта может быть нecколько архитектур, соответствующих разным алгоритмам функционирования, проектам на различных этапах проектирования. Такая структура программ VHDL позволяет строить библиотеки объектов, процедур, типов и т.п., выполнять программирование проекта в произвольном порядке: снизу-вверх или сверху-вниз, а также параллельно нecколькими программистами, использовать объекты из других проектов, тестировать проекты по одинаковой методике.

Расмотрим программирование проекта приоритетного шифратора. На вход шифратора поступают сигналы А1, …,А7 , а на выход выдаются сигналы Y2,Y1,Y0, которые кодируют номер входного сигнала, причем у А7 – наивысший приоритет. Т.е. при поступлении лог.1 на А7 и любой комбинации на остальные входы код Y2,Y1,Y0=111, при поступлении лог.0 на А7 , лог.1 на А6 и любой комбинации на остальные входы - код Y2,Y1,Y0=110 и т.д. Объект проекта выглядит как:

library std ; -- описание: используемая стандартная библиотека STD
use std.standard.all; -- описание: используются все типы из пакета STANDARD библиотеки STD
entity PRIORITY is -- название объекта - PRIORITY
port( --объявление портов
A1 : in BIT; -- входной порт А1 типа BIT
A2 : in BIT;
A3 : in BIT;
A4 : in BIT;
A5 : in BIT;
A6 : in BIT;
A7 : in BIT;
Y1 : out BIT; -- выходной порт Y1 типа BIT
Y2 : out BIT;
Y0 : out BIT );
end PRIORITY; -- конец объявления объекта

Так как библиотека STD – стандартная, она встроена во все симуляторы и может быть указана неявно. Для других библиотек, которые используются при описании объекта, нужно использовать их описание library и use. Здесь они приведены для примера.

Ключевое слово port открывает описание входов-выходов (портов) объекта. Слово in указывает на вход, а out – на выход. BIT – это тип порта, который, согласно определению этого типа в пакете standard, принимает значения 0 и 1.

Название объекта вначале и в конце – обязательно. Это дополнительная рутина, зато удобно для различения объектов, если их описание занимает много места, - как открывающаяся и закрывающаяся скобка особенного типа.

Описание архитектуры:
architecture HALLO of PRIORITY is -- начало архитектуры HALLO объекта PRIORITY
--декларативная часть архитектуры
signal t1,t2,t3,t4,t5,t6,t7:BIT; --объявление используемых сигналов
begin --начало описательной (поведенческой) части архитектуры
-- Y2Y1Y0
--A7 --1 1 1
t1<= not A7 and A6; -- 1 1 0
t2<= not A6 and A5 and not t1; -- 1 0 1
t3<= not A5 and A4 and not t1 and not t2; -- 1 0 0
t4<= not A4 and A3 and not t1 and not t2 and not t3; -- 0 1 1
t5<= not A3 and A2 and not t1 and not t2 and not t3 and not t4; -- 0 1 0
t6<= not A2 and A1 and not t1 and not t2 and not t3 and not t4 and not t5; -- 0 0 1
Y0<= A7 or t2 or t4 or t6;
Y1<= A7 or t1 or t4 or t5;
Y2<= A7 or t1 or t2 or t3;
end HALLO; --конец архитектуры

Раздел архитектуры состоит из декларативной и описательной частей. В декларативной части объявляются используемые внутри объекта сигналы, константы, специальные (свои собственные) типы, атрибуты, процедуры и функции, описания этих атрибутов, процедур и функций. Описательная часть состоит из списка параллельных операторов. Все параллельные операторы выполняются одновременно. Их порядок в списке не имеет другого значения, кроме значения, определяемого вкусом программиста.

В параллельных операторах процесса стоят последовательные операторы, выполняемые по очереди, как в программах на обычных языках. Схемы с памятью, например, триггер, регистр, ОЗУ моделируются с помощью оператора процесса или оператора вставки компонента с функцией памяти, описанного парой объект-архитектура в другом месте.

В данной программе все операторы – операторы параллельного присваивания, обозначенные символами "<=", которые сигналам присваивают значение выражения справа. Здесь в выражениях используются функции and, or и not. Hад операндами типа BIT определены еще функции nand, nor, xor, xnor. А функции сравнения "=" и "/=" - возвращают результат типа boolean со значениями true, false. Для задания четкого порядка выполнения функций в выражениях следует использовать скобки.

Эта архитектура написана стилем потоков данных, т.е. в ней использованы только параллельные операторы, кроме операторов процесса и вставки компонента. Здесь операторы как бы указывают потоки данных между линиями связи, обозначенными идентификаторами сигналов, а также обработку этих потоков.

Для проверки правильности проекта обычно используют испытательный стенд (testbench). Это тоже пара: объект – архитектура, в которой испытуемый блок использован как компонент. В Active HDL есть функция генерации испытательного стенда, которая генерирует его заготовку. Такая заготовка состоит из оператора включения испытуемого блока и набора сигналов, которые подключены к блоку. Остается только добавить операторов для генерации входных сигналов и возможно, для проверки выходных сигналов блока. Испытательный стенд для блока PRIORITY(HALLO):

entity priority_tb is --пустой объект, т.к. входов-выходов нeт
end priority_tb;

architecture TB_ARCHITECTURE of priority_tb is
component priority(hallo) -- компонент, который будет испытываться
port( -- выглядит почти так же, как объявление объекта проекта
A1 : in BIT;
A2 : in BIT;
A3 : in BIT;
A4 : in BIT;
A5 : in BIT;
A6 : in BIT;
A7 : in BIT;
Y1 : out BIT;
Y2 : out BIT;
Y0 : out BIT );
end component; -- сигналы внутри испытательного стенда
signal A1 : BIT:='0'; --сигнал объявлен с начальным состоянием = 0;
signal A2 : BIT:='0'; -- начальное состояние можно было бы не объявлять -
signal A3 : BIT:='0'; -- у битового типа и так симулятор назначает начальное состояние=0. signal A4 : BIT:='0'; -- В реальных проектах сигналы типа STD_LOGIC
signal A5 : BIT:='0'; -- и им симулятор по умолчанию назначает начальное состояние
signal A6 : BIT:='0'; -- = U - " не инициализированное "
signal A7 : BIT:='0'; -- поэтому для таких сигналов желательно объявить
signal Y1 : BIT:='0'; -- начальное состояние по своему усмотрению
signal Y2 : BIT:='0';
signal Y0 : BIT:='0';

begin -- описательная часть архитектуры

UUT : priority -- параллельный оператор вставки компонента
port map ( -- поименованное связывание портов и сигналов
A1 => A1, --порт А1 подключен к сигналу А1
A2 => A2,
A3 => A3,
A4 => A4,
A5 => A5,
A6 => A6,
A7 => A7,
Y1 => Y1,
Y2 => Y2,
Y0 => Y0
);
-- это операторы присваивания сигналу - генерируют тестовые сигналы
A1<= not A1 after 2 ns; -- оператор инвертирует сигнал,
--затем ждет 2нс и опять инвертирует и т. д. до бесконечности
A2<= not A2 after 4 ns;
A3<= not A3 after 6 ns;
A4<= not A4 after 8 ns;
A5<= not A5 after 10 ns;
A6<= not A6 after 12 ns;
A7<= not A7 after 14 ns;

end TB_ARCHITECTURE;

Эта программа запускается на моделирование и в окне графиков (waveform window) можно увидеть следующие графики:

Эти графики показывают, что модель приоритетного шифратора работает правильно. Если архитектура объекта PRIORITY претерпит изменения или модернизацию, то на этом испытательном стенде можно ее проверить опять, ничего в нем не меняя.

Итак, в данной статье рассмотрены основы программирования на VHDL и получена работоспособная, синтезируемая модель приоритетного шифратора. Эту модель можно совершенствовать, изменять число и функциональность портов ввода-вывода и т.п. Так что, согласно методике Hallo, World, можно сказать, что VHDL – это очень просто.


VHDL

Что такое VHDL

Кратко о VHDL

Традиционно одним из этапов пректирования средств вычислительной техники является разработка электрических схем. Эта ответственная работа связана с большими трудозатратами, контролем правильности и соответствия задуманному проекту, необходимостью четкого и емкого описания созданных схем, трудностями с их сопровождением и модернизацией. САПР вычислительной техники, как правило, имеют средства ввода и редактирования схем. Однако два десятилетия назад при разработке СБИС отказались от схемного проектирования.

Язык Very high speed integrated circuits Hardware Description Language (VHDL) был разработан в 1983 г. по заказу Министерства обороны США с целью формального описания логических схем для всех этапов разработки электронных систем, начиная модулями микросхем и кончая крупными вычислительными системами. Он является стандартным языком с 1987 г. Стандартом 1993 г. закреплены многие его усовершенствования [1]. Наряду с языком Verilog он является базовым языком при разработке аппаратуры современных вычислительных систем.

В чем преимущества VHDL над схемным проектированием?

Проектирование больших вычислительных устройств (ВУ) - С помощью VHDL проще и быстрее ввести и проверить большой проект. Десятью строками VHDL можно описать как 1, так и 100000 триггеров. Микросхему с интеграцией более 10000 вентилей разработать только с помощью электрических схем очень трудно по причине громоздскости схем.

Проект на VHDL -объединение структуры ВУ и алгоритма его функционирования. Для ВУ, описанного на VHDL, необязательно выполнять проверку правильности его функционирования, например, путем его макетирования. Чтобы определить, правильно ли ВУ выполняет заданный алгоритм, достаточно его VHDL -программу запустить на исполнение в симуляторе VHDL. Соответствующие САПР преобразуют VHDL-описание в комплект документации для изготовления работоспособного устройства.

Проект на VHDL - самодокументированный, т.е.он не требует дополнительного технического описания или в виде схем. Нечеткость и небрежность описания исключаются, так как проект на VHDL несложно проверить.

Высокая надежность проекта. Синтаксический анализ, моделирование и компиляция в логическую схему быстро выявляют ошибки проекта.

Проект на VHDL - универсальный проект. Разработанный однажды вычислительный блок может быть использован во многих других проектах. При этом многие сруктурные и функциональные параметры блока могут быть настраиваемыми (параметры разрядности, объема памяти, элементная база, состав блока и структура межсоединений).

Проект на VHDL - портативный проект. Разработанный для одной элементной базы, проект ВУ без труда переносится на другую элементную базу, напр. СБИС с различной технологией.

Проект на VHDL - долгоживущий проект. Электрическая схема всегда разрабатывается под конкретные элементную базу и интерфейс. Так как элементная база сменяется за период 2-5 лет, за этот же период устаревают и электрические схемы, ее использующие. Проект ВУ на VHDL может быть повторно использован через несколько лет. Хорошее техническое решение (напр., изобретение), описанное на VHDL, может быть востребованным в течение десятилетий.

VHDL - универсальное средство описания ВУ на уровнях:

  • алгоритмическом,
  • структурном,
  • регистровых передач (RTL) и потоков данных (dataflow),
  • логическом,
  • аналоговых схем.

Ход проектирования с использованием VHDL.

На рисунке показана схема разработки проекта ВУ, предназначенного для исполнения в программируемой логической интегральной схеме (ПЛИС).

Вначале ВУ описывается в виде своей поведенческой модели, на которой отрабатывается задуманный алгоритм функционирования ВУ. Затем эта модель вручную перерабатывается в синтезируемую модель ВУ, описанную на уровне регистровых передач. Такая модель, будучи странслированной компилятором-синтезатором, дает проектную документацию в виде файла описания схемы ВУ на уровне вентилей (EDIF - файл). При этом автоматически выполняется логическая оптимизация ВУ. Одновременно этот файл автоматически преобразуется в VHDL- модель ВУ на уровне вентилей.

Проект ВУ в виде Electronic Distribution International Format (EDIF) - файла принимается как исходный всеми САПР изготовления ПЛИС и СБИС. Эти САПР выполняют замену вентилей на библиотечные компоненты, их размещение на площади кристалла, трассировку межсоединений, проектирование масок, проверку соответствия проектным нормам и т.п. В результате записываются файлы проектной документации изготовления кристалла и его логической модели, учитывающей задержки как в вентилях, так и в межсоединениях. Эта модель также представляется на VHDL.

Стоимость ошибок при проектировании СБИС очень высока, особенно на ранних этапах. Поэтому все этапы проектирования - алгоритмический, структурный, логический, технологический - сопровождаются моделированием ВУ с помощью, так называемого испытательного стенда (testbench). Этот стенд представляет собой VHDL-модель, составными частями которой являются модель тестируемого ВУ и модели генератора тестовых сигналов и логического анализатора, проверяющих правильность функционирования ВУ. Причем на всех этапах может использоваться один и тот же испытательный стенд и те же тестовые файлы.

По каким причинам VHDL используется в современных САПР микроэлектроники?

Исторически сложилось, что в микроэлектронной индустрии наибольшее распространение получил язык Verilog. Полтора десятилетия назад этот язык выиграл конкурентную борьбу с другими языками задания ВУ, благодаря небольшим требуемым вычислительным ресурсам прежних рабочих станций и достаточно точным результатам моделирования СБИС. VHDL - более универсальный и гибкий язык, но он проигрывал в быстродействии языку Verilog, особенно при моделировании на уровне вентилей и транзисторов. VHDL получил широкое распространение в университетах и исследовательских учреждениях, так как это строгий, стройный, универсальный и расширяемый язык. Так, например, появились пакеты VHDL для аналогового моделирования, моделирования многозначной логики. Кроме того, симуляторы VHDL были гораздо дешевле симуляторов Verilog.

Все современные САПР микроэлектроники имеют компиляторы как с Verilog, так и с VHDL. Программист, освоивший VHDL, без особого труда может перейти к программированию на языке Verilog. В отличие от обратного.

Важнейшими качествами VHDL в САПР выступают следующие:

Гибкость. Проект, описанный на VHDL, может быть легко настроен под конкретные задачи потребителя. Универсальный язык. VHDL - общепринятый язык для всех основных фирм - изготовителей микросхем ПЛИС, ПЛМ, заказных СБИС как стандартный язык для задания сложных проектов. Проектирование с VHDL - устойчивая тенденция в инженерной технологии. Существуют компиляторы, транслирующие VHDL- программы в эквивалентные им Verilog - программы.

Моделирование с учетом задержек. Фирмы - изготовители микросхем в своих САПР обеспечивают генерацию моделей результатов размещения и трассировки, описанных на VHDL.

Стандартное подключение блоков. Конструкции языка, такие как entity, port map, configuration, обеспечивают надежную и быструю стыковку блоков, разработанных разными фирмами и разработчиками, в различном сочетании.

Стандартное тестирование. На всех этапах разработки выполняется тестирование по одной методике одними и теми же тестами.

VHDL - стандарт будущего. Все новые САПР основаны на технологии трансляции описания ВУ на языке описания аппаратуры. Использование VHDL - гарантия того, что через 5 и 10 лет найдется САПР, поддерживающая старые разработки.


VHDL

VHDL - FPGA

Технология разработки систем на кристалле

Согласно известному закону Мора, количество транзисторов на кристалле СБИС с каждым годом увеличивается приблизительно на 60%. С определенного момента времени то оборудование, которое размещалось на одной печатной плате, стало возможным поместить на одном кристалле (рис.2). Причем это становится выгодным, благодаря уменьшению общей стоимости, числа необходимых микросхем, энергопотребления, повышению надежности. Таким образом, на одном кристалле размещается не только конкретное функциональное устройство, например, центральный микропроцессор, но и другие, такие как АЦП, ОЗУ, ПЗУ, блоки цифровой обработки сигналов, интерфейсные узлы и т.п., дополняющие его до законченной системы блоков. Поэтому такое ВУ принято называть System On the Chip (SOC) - системой на кристалле (СНК).

СНК это, как правило, заказная СБИС. Чтобы разработка СНК себя окупила, необходимо реализовать десятки и сотни тысяч СБИС. Проект ВС, реализованный на ПЛИС, может быть выгодным при партиях в десятки и сотни экземпляров, благодаря дешевизне разработки и производстава такой ВС. Разработка такой ВС как минимум в 2 раза длится быстрее, чем проектирование СБИС. Это обусловило бурное распространение ПЛИС как элементной базы СНК.

Наиболее трудоемкими и ответственными этапами разработки СНК выступают этапы структурного проектирования и верификации соответствия ВС заданным алгоритмам функционирования. Поэтому эффективность САПРов микросхем и производительность разработчиков, выполняющих проектирование на уровне регистровых передач, постоянно растет приблизительно на 20% в год. Но начиная с середины 90-х годов, производительность разработчиков стала заметно отставать от роста сложности СНК .

Первым направлением улучшения технологии разработки СНК, направленным на уменьшение зазора между ростом производительности проектирования на уровне регистровых передач и ростом сложности СНК, является применение крупных библиотечных вычислительных модулей (Intellectual Property Cores). Эти модули должны быть надежно повторяемыми и настраиваемыми под решаемые задачи в ряде проектов СНК. Повторное применение таких модулей (IP Core reuse), которые можно назвать вычислительными заготовками за их функциональную и технологическую адаптируемость, позволяет уменьшить трудозатраты и сроки проектирования СНК.

Второе направление - это разработка САПР совместного проектирования аппаратно-программного обеспечения (Hardware - Software Codesign). Архитектура СНК, как правило, включает в себя микропроцессорное ядро с периферийными устройствами в различном сочетании. Обычно процесс разработки ВУ с такой архитектурой состоит из трех последовательных этапов: разработки матобеспечения микропроцессора, проектирования электрической схемы аппаратуры и стыковки матобеспечения с аппаратурой. Для ускорения проектирования разрабатывают САПР, которая не только обеспечивает совместное выполнение этих этапов, но и моделирование работы СНК и ее верификацию в комплексе.

Наибольшее ускорение разработки СНК может дать внедрение САПР непосредственного отображения алгоритмов в аппаратуру, т.е. САПР системного проектирования. Например, такая САПР может включать в себя трансляцию программы с языка высокого уровня, например, С++ , с автоматическим разделением вычислительных задач между микропроцессорным ядром и спецпроцессорами и другими периферийными устройствами.

Вычислительные заготовки

В крупных фирмах, долгие годы занимающихся разработкой СБИС, а теперь и СНК, наработаны большие библиотеки стандартных модулей, как-то: ОЗУ, АЛУ, периферийные устройства. В новых проектах СНК некоторые блоки приходится разрабатывать заново, а остальные - берутся из библиотеки. При этом если модуль неясно описан, не имеет хорошего интерфейса, документации, комментариев, испытательного стенда с надежными тестами, то он повторно применяться не будет. Если такой модуль изначально оформлен в виде вычислительной заготовки, то он будет без лишних проблем вставляться в любой новый проект. Более того, лицензию на него можно предлагать другим фирмам - разработчикам СНК. Рисунок иллюстрируют суть вычислительной заготовки (IP core).

Вычислительные заготовки различаются по степени гибкости своей настройки под условия потребителя как:

  • гибкие (описанные языком описания аппаратуры, таком как VHDL, на уровне регистровых передач),
  • жесткие (логическая схема, EDIF - файл) и
  • твердые (маски под определенную технологию, прошивки ПЛИС).

Гибкие заготовки обычно подстраиваются к условиям нового проекта в широких пределах и независимы от его технологии (серия ПЛИС, технология СБИС). Минимизация аппаратурных затрат вычислительных заготовок обеспечивает не только уменьшение стоимости СНК, но и уменьшение его энергопотребления, что является важным фактором для портативных и энергонезависимых приложений.

Чтобы проект ВУ был принят как гибкая вычислительная заготовка, он должен иметь:

  • исчерпывающую и ясную документацию;
  • текст описания на VHDL или Verilog в хорошем стиле для синтеза, заготовка должна быть настраиваемой под технические условия потребителя;
  • хорошие средства верификации в виде испытательных стендов, исчерпывающих тестов, возможно, опытных макетов;
  • четкую методику того, как ВУ вставлять в СНК, включающую надежные скрипты (программы на макроязыке САПР, автоматизирующие тестирование и создание жесткой или твердой заготовки) [1].

В сегодняшних условиях, чтоб быстрее перейти от идеи к "железу", эффективнее провести проектирование новой СНК, необходимо эту СНК "собрать" из имеющихся вычислительных заготовок , а отсутствующие - приобрести на рынке IP cores, который бурно развивается в последние годы. Если приобрести не удастся или если проект - исследовательский, то необходимую заготовку можно поискать, например, в банке бесплатных IP cores, что на сайте www.opencores.org. Этот банк создан по инициативе организаций, содействующих развитию технологии СНК, а также инженеров, желающих поделиться своими результатами. Если оба этих пути не устраивают, то прийдется ВУ проектировать самостоятельно и данная книга может этому помочь.


VHDL

Программистская модель вычислителя VHDL

Начинающий программист VHDL легко осваивает структурный стиль программирования, которым формально описывается структура моделируемого устройства. Без трудностей он программирует стилем потоков данных, описывая операторами параллельного присваивания прохождения данных через некоторую комбинационную схему. Но при переходе к поведенческому стилю, основанному на операторах процессов, нередко возникают сложности с пониманием выполнения этих операторов, программированием желаемого поведения системы и отладкой составленной программы.

Он знает, что VHDL - это язык программирования. Но у него возникает вопрос, программирования чего? При программировании на Си программист должен представлять, что он с помощью этого языка описывает задуманный алгоритм для его реализации на неймановской модели ЭВМ, содержащей, АЛУ, регистровую, оперативную, дисковую память и т.д., что существуют определенные типы данных и механизмы доступа к ним. Другими словами, он программирует некоторую программистскую модель вычислителя для реализации данного языка. Безусловно, для успешного программирования на этом языке необходимо досконально знать программистскую модель соответствующего вычислителя, т.е. его архитектуру.

Составление программы VHDL означает программирование модели вычислителя, выполняющего эту программу. Поэтому далее рассмотрим программистскую модель вычислителя для реализации языка VHDL. Собственно, алгоритм, описанный на VHDL, представляет собой некоторое множество вычислительных процессов, организованных на определенной модели вычислителя. Кроме того, для понимания реализации VHDL в симуляторах используется модель вычислителя с точки зрения разработчика симуляторов. Наконец, при синтезе логических схем рассматривается аппаратная модель реализации VHDL, т.е. модель, реализуемая в СБИС или ПЛИС.

Наиболее полно программистская модель вычислителя VHDL описана в руководстве к стандарту языка (VHDL'93. IEEE Standard VHDL Language Reference Manual или сокращенно - LRM) . В нем параллельно с описанием синтаксиса и семантики всех языковых конструкций приводятся объяснения их реализации в модели вычислителя. Но, изучая это руководство, с первого раза, трудно постичь основы этой модели. LRM предполагает, что читатель будет его листать из начала - в конец, из конца - в середину, из середины - вперед и т.д. несколько итераций, пока не возникнет понимание целостной картины языка. Наверное, за это VHDL и не любят, так как такая методика его освоения вызывает к нему отвращение. С другой стороны, тот, кто постиг основы VHDL, чувствует себя более свободным в обращении с ним.

Ниже описывается упрощенная модель вычислителя VHDL, которая содержит основные особенности этой модели и не противоречит модели, описываемой в LRM.

В отличие от большинства современных языков программирования, язык VHDL основан на параллельной многопроцессорной модели. Нижний уровень модели образует архитектура виртуального процессорного элемента (ВПЭ), а верхний уровень - множество ВПЭ, объединенных некоторой запрограммированной системой межпроцессорных связей.

Структура ВПЭ состоит из арифметико-логического устройства (АЛУ), ОЗУ данных (ОЗУД), ОЗУ программы (ОЗУП) и определенного количества источников (ИС) и приемников (ПС) сигналов.

АЛУ выполняет такой же набор операций, какой требуется для реализации большинства языков программирования, как, например, сложение, умножение, деление с фиксированной и плавающей запятой, логические операции и т.д. Кроме того, АЛУ выполняет многие другие операции, специфические для VHDL, такие как операции над данными с произвольной заданной разрядностью, с многозначным логическим представлением разрядов. При этом постоянно проверяется корректность результата операции, и фиксируются ошибки как-то: выход за заданный диапазон представления числа, несовпадение типов операндов и результатов получение ошибочного результата и т.п.

В ОЗУ данных хранятся переменные, участвующие в вычислениях. Переменные имеют статические адреса, но при необходимости можно реализовать динамический доступ к переменным. Источники и приемники сигналов служат, в основном, для связи ВПЭ с внешним миром. При поступлении сигнала на вход приемника сигнала он фиксирует это событие. В приемнике хранится как текущее, так и предыдущее состояние сигнала. При выполнении операции с идентификатором сигнала, как с операндом, выполняется чтение приемника сигнала. После выполнения оператора присваивания сигналу источник сигнала генерирует соответствующий сигнал.

В ОЗУ программы хранится программа в виде цепочки операторов. Операторы, включая условные операторы, выполняются последовательно друг за другом, как в обычных языках программирования. Но на операторах wait выполнение программы останавливается.

Операндами оператора wait являются набор входных сигналов, так называемый список чувствительности, или заданный промежуток времени задержки, или булевское выражение от некоторых данных.

Оператор wait ожидает появления внешнего события: прихода сигналов, удовлетворяющих определенным условиям или истечения срока заданной задержки. После появления внешнего события программа продолжает выполнение со следующего оператора. Только при выполнении оператора wait в источниках сигналов генерируются сигналы, которым в программе было присвоено новое значение. При достижении последнего оператора программа переходит к своему первому оператору.

Такая программа записывается в VHDL-программе как один параллельный оператор, называемый процессом, а ВПЭ выполняет его как вычислительный процесс.

Отдельным входом-выходом ВПЭ является шина передачи глобальных (shared) переменных. Глобальная переменная может приниматься (участвовать как операнд) или передаваться из ПЭ (как результат операции присваивания) в произвольные моменты времени. В языке не предусмотрены механизмы синхронизации передачи глобальных переменных. Поэтому их применение ограничено, например, рассылкой общего начального значения, работой с файлами.

К ВПЭ можно подключать дисковую память. При этом операторы открытия, чтения, записи, закрытия файлов используются аналогично, как в других языках.

Верхний уровень программистской модели составляет множество ВПЭ, объединенных линиями связи, по которым передаются сигналы. Общими для всех ВПЭ являются консоль для связи с оператором-программистом (клавиатура и дисплей), дисковая память и ОЗУ глобальных переменных.

Количество ВПЭ в системе равно числу процессов в программе VHDL после её компиляции. Линий межпроцессорной связи в структуре системы столько, сколько необходимо для исполнения VHDL-программы.

Как и в других языках параллельного программирования, в VHDL сигнал используется одним вычислительным процессом для сообщения другим вычислительным процессом факта исполнения

некоторого события. Кроме того, сигнал используется для передачи исходных и промежуточных данных между процессами. Наконец, при использовании VHDL-программы выбранные сигналы можно записать в своем развитии и затем воспроизвести в виде временных графиков или таблиц.

При запуске программы на исполнение вначале все переменные принимают заданное начальное значение. Затем во всех ВПЭ начинают свое исполнение вычислительные процессы. При достижении операторов wait ВПЭ генерируют вычислительные сигналы и останавливаются. Эти сигналы, пройдя через соответствующие им линии связи до других ВПЭ, запускают в них продолжение вычислительных процессов. Такое функционирование вычислительной системы может продолжаться неопределенно долго, пока оно не будет остановлено с консоли.

В большинстве программ VHDL один из процессов является ведущим и задает поток возбуждающих состояний сигнала для других процессов. Например, этот процесс моделирует генератор синхросерии. Тогда ВПЭ - генератор возбуждающего сигнала - запускает смежные с ним ВПЭ. Эти ВПЭ запускают ВПЭ следующие за ними и т.д. Таким образом, по вычислительной системе проходят волны запусков. Следовательно, модель вычислителя для реализации VHDL можно трактовать как некоторый волновой процессор со специализированной топологией.

Если в процессе не использованы операторы wait с установленной задержкой, то цикл запуска-остановки этого процесса выполняется почти мгновенно, а точнее - с дельта-задержкой. Здесь дельта-задержка - исчезающе малый промежуток времени, одинаковый для всех таких процессов.

Основным назначением консоли является вывод сообщений на экран, которые генерируются специальными операторами assert и report.

ВПЭ могут иметь произвольный доступ записи-чтения к памяти глобальных переменных. Эти переменные служат дополнительным средством связи между ВПЭ, так как внутренние переменные в ВПЭ недоступны для других элементов вычислительной системы. ВПЭ функционируют асинхронно относительно друг друга и поэтому невозможно задать однозначный порядок доступа к глобальной переменной от нескольких ВПЭ без искусственного введения механизмов синхронизации. Поэтому корректное использование глобальной переменной возможно, если она используется как константа или запись в нее выполняется только одним ВПЭ, причем если момент записи безразличен относительно вычислительных процессов в других ВПЭ.

При программировании необходимо учитывать следующее.

  • Все процессы исполняются параллельно.
  • " Одновременно исполняемые процессы образуют фронт волны запусков процессов. Этот фронт передвигается с временным шагом, равным дельта-задержке.
  • " Все параллельные операторы языка VHDL преобразуются в функционально эквивалентные операторы процессов, поэтому данная вычислительная модель годится для произвольной VHDL-программы.
  • Структура вычислительной модели остается неизменной после компиляции программы, т.е. после своего формирования. Эта структура не зависит от сигналов и переменных, изменяемых в процессе выполнения программы, т.е. она не может перестраиваться динамически.
  • Область действия всех переменных (кроме глобальных) ограничена рамками операторов процесса. Вне процессов переменные невидимы.
  • Порядок доступа к глобальным переменным непредсказуем. Следует с осторожностью программировать с этими переменными. Желательно отказываться от их использования в программах.


VHDL

Атрибуты.

Атрибутом называют особенное, долговременное свойство предмета. В языке VHDL сигналы, переменные и другие объекты, кроме своего значения, также имеют множество атрибутов. У каждого типа объектов есть несколько предопределенных атрибутов. Пользователь также может ввести ряд специальных атрибутов. Атрибуты бывают различного типа: атрибут – тип, значение, сигнал, функция, диапазон.

Атрибут объекта записывается как

\имя объекта\' \имя атрибута\ .

Ниже рассматриваются некоторые предопределенные атрибуты.

Атрибуты для скалярного типа.

Для скалярного типа Т предопределены следующие атрибуты:

T'left – самое левое значение множества элементов скалярного типа Т.

T'right – самое правое значение множества элементов скалярного типа Т.

T'high – наибольшее значение в множестве элементов скалярного типа Т.

T'low –наименьшее значение в множества элементов скалярного типа Т.

T'image(X) – функция строкового представление выражения Х типа Т.

T'value(Х) – функция значения типа Т от строкового представления Х.

T'pos(Х) – функция номера позиции элемента Х типа Т.

T'val(Х) –функция значения элемента типа Т стоящего в позиции Х.

Примеры атрибутов:

type st is (one,two,three);

st'right = three, st'pos(three) = 2, st'val(1) = two.

positive'low = 1, positive'high =2147483647.

integer'value("1_000") =1000, integer'image(330) ="330".

Атрибуты для регулярного типа.

Для регулярного типа A предопределены следующие атрибуты:

A'left[(N)] – левое значение диапазона индексов по N-й размерности.

A'right[(N)] - правое значение диапазона индексов по N-й размерности.

A'high[(N)] - наибольшее значение диапазона индексов по N-й размерности.

A'low[(N)] - наименьшее значение диапазона индексов по N-й размерности.

A'range[(N)] – диапазон индексов по N-й размерности.

A'reverse_range[(N)] – обратный диапазон индексов по N-й размерности.

A'length[(N)] – протяженность диапазона индексов по N-й размерности.

A'ascending[(N)] - функция, равная true, если диапазон индексов по N-й размерности - возврастающий.

Примеры применения атрибутов:

type s2 is array(2 downto 1, 0 to 3) of integer;

s2'left(1) = 2,
s2'right(2) = 3,  s2'high(1) = 2,
s2'low(2) = 0,

s2'range(2) = 0 to
3,  s2'reverse_range(1) = 1 to 2,
s2'length(2) = 4.

Атрибуты сигналов

Атрибуты сигналов S:

S'stable[(T)] – сигнал, равный true, если за промежуток времени Т не было событий у сигнала S.

S'transaction – сигнал типа bit, меняет значение на противоположное в циклах моделирования, в которых было присваивание нового значение сигналу S.

S'event – сигнал, равный true, если произошло событие в сигнале S в данном цикле моделирования.

S'active – сигнал, равный true, если произошло присваивание нового значение сигналу S в данном цикле моделирования.

S'last_value – сигнал такого же типа, что и S, содержащий значение S до последнего события в нем.

Примером применения атрибутов сигналов является следующий процесс, моделирующий синхронные триггеры.

process(CLK) begin

if CLK='1' and CLK'event then-- D- триггер

q1<=a;

end if;

if not CLK'stable then -- D- триггер

q2<=a;

end if;

if CLK'last_value /= CLK then-- D- триггер

q3<=a;

end if;

if CLK'active-- D- триггер

q4<=a;

end if;

q5<=CLK'transaction; -- T- триггер

end process;

Атрибуты пользователя.

Эти атрибуты предназначены для присваивания объектам языка дополнительных свойств, не предусмотренных встроенными типами и атрибутами. При проектировании дискретных устройств такими свойствами могут быть способ кодирования состояний автомата, указания компилятору – синтезатору по управлению оптимизацией, размещению блоков, их исполнению, назначение портов номерам выводов, начальное состояние схем памяти и т.п. Т.е. эти свойства не связаны напрямую с алгоритмом, реализуемым в программе. Задание атрибута состоит из его объявления и спецификации.

Объявление атрибута имеет синтаксис, похожий на объявление переменной:

\объявление атрибута\::=atribute \идентификатор\ : \ тип\

где \тип\ - любой ранее определенный тип, например, string, positive, time.

Спецификация атрибута имеет синтаксис:

\спецификация атрибута\::=attribute \идентификатор\ of

\имя объекта\[{,\имя объекта\}] | others | all : \класс объекта\ is \выражение\

\имя объекта\::= ((\идентификатор\ |\символьный литерал\ | \символ оператора\)

[\сигнатура\])

\класс объекта\::= entity | architecture | configuration | package | procedure | function | type | subtype | constant | signal | variable | file | component | label | literal | units | group

Здесь \идентификатор\ - имя атрибута, объявленнного ранее, \имя объекта\ - имя объекта, которому присоединен атрибут. \сигнатура\ - это список типов параметров, если объектом является процедура, функция или перечисляемый литерал, предназначенный для идентификации перезагружаемых процедур, функций и литералов.

Спецификация атрибута обычно вставляется сразу же после объявления этого атрибута.

Атрибуты пользователя обычно не влияют на поведение модели и такие атрибуты игнорируются симулятором. Но они имеют большое значение для компилятора – синтезатора и для средств реализации схемы в кристалле. Поэтому, как правило, фирмы – поставщики компиляторов и производители микросхем предлагают для использования свои наборы атрибутов пользователя. В следующем примере атрибут указывает способ кодирования состояний автомата:

type \состояние\ is ( \сброс\,\начало\,\работа\,\конец\);

attribute enum_encoding : string;

attribute enum_encoding of \состояние\ : type is "000 001 010 100" ;

Атрибут foreign.

Специальный атрибут foreign присоединяется к архитектуре, процедуре или функции. Он указывает симулятору, что соответствующий объект должен моделироваться особенным способом. Это может быть специальная программа на ассемблере или другом языке, или аппаратный ускоритель.


VHDL

Ещё один тахометр

Редкий радиолюбитель, владелец автомобиля, не полезет в него с паяльником. Вот и размножаются сотнями любительские схемы разных блоков зажигания, октан-корректоров, тахометров, зарядных устройств, охранной сигнализации. Некоторые идут дальше – и появляются бортовые компьютеры, телевизионные зеркала заднего обзора и даже устройства распознавания знаков дорожного движения.

В данной статье не будет предлагаться автомобильная навигационная система. Просто - ещё один тахометр. Тахометр - это измеритель числа оборотов двигателя за единицу времени. Входные данные Fx поступают с датчика числа оборотов, которым чаще всего является прерыватель системы зажигания или емкостной датчик импульсов напряжения в свечных проводах. Результат измерения получают путем интегрирования импульсов одинаковой длительности в аналоговой схеме или простым подсчетом импульсов за единицу времени в частотомере.

Но частота Fx слишком низкая для измерения с точностью до 3-5 десятичных цифр в реальном масштабе времени. Измерение частоты на выходе генератора переменного тока бортовой сети не решает проблему кардинально. Кроме того, ещё необходима коррекция результата измерения путем умножения на масштабный коэффициент, т.е.Y=M*Fx. Выход в том, что необходимо измерять период Тх сигнала, а измеряемую величину находить как результат деления Y=M/Tx.

Для вычисления Y=M/Tx существует очень простой и удобный алгоритм. Если из большеразрядного целого М вычитать малоразрядное Тх до тех пор, пока М не приблизится к нулю, то число вычитаний будет равно искомому Y. При этом счетчик числа этих вычитаний можно выполнить по любому основанию, например, по основанию 2, 10, в кодах 7-сегментных индикаторов, в унитарном коде, т.е. коде бегущей единицы, в коде отображения столбика единиц и т.п.

Недостатком алгоритма является его высокая алгоритмическая сложность, т.е. то, что для получения 3-5 – разрядного десятичного результата необходимо выполнить до 1 –100 тыс. вычитаний и столько же сложений с единицей на одно измерение или 0.1 – 100 млн. операций в секунду, в зависимости от быстродействия измерений. Это довольно сложно для микроконтроллера, зато совсем нетрудно для ПЛИС и даже CPLD.

Здесь приводится простая модель тахометра. Модель представлена в Приложении. Тахометр работает периодически с последовательным повторением четырех фаз. В фазе Waiting ожидается фронт входного сигнала, в фазе Measure измеряется период сигнала Period как число тактов синхросерии между двумя соседними фронтами входного сигнала. При этом период меньше measureMIN не фиксируется, так как в нем могут быть импульсы дребезга контактов. В фазе Calculate вычисляется частота F= Masstab/Period . Эта частота F вычисляется в виде кода столбика единиц, который пригоден для непосредственного вывода на линейный светодиодный индикатор. В фазе Display ничего не происходит, кроме вывода результатов измерения.

Частота синхросерии равна 6,8 кГц. Она может быть подстроена выбором констант Masstab, measure_T, а также повышена при использовании дополнительного делителя частоты.

Такой тахометр помещается в любой корпус ПЛИС или CPLD . Он без особенной оптимизации занимает 125 LUT и 71 триггер. Так что весь прибор занимает один корпус CPLD XC9572 и генератор синхроимпульсов, не считая индикатора. Кстати, выходного тока ПЛИС или CPLD достаточно для прямого подключения светодиодов.

Если датчиком является прерыватель или емкостный датчик на проводе свечи зажигания, то на выходе такого датчика присутствуют высоковольтные импульсы. Хотя входы микросхемы защищены от высоковольтного низкотокового воздействия, следует вход микросхемы защитить от перенапряжения, например, резисторным делителем напряжения с диодным стабилизатором.

                    Приложение

--^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
--  FILE: TAСHOMETER.VHD
--  PROJECT: VHDL_HOBBY
--  AUTHOR:       Anatoli Sergyienko
--  Created:            15/01/02
--  Email:        aser@comsys.ntu-kpi.kiev.ua
--
--  FUNCTION: - measuring and displaying the rotating frequency
                --of the car engine.
--  ALGORITHM: 1. Period of the signal DATAI is measured in clocks
--             2. frequency is calculated as F= Masstab/Period
--             3. frequency is outputted through DATAO to the
--               barcode display
--  CONSTRAINTS: the barcode display length is limited by Fmax,
--     maximum period of the signal is measure_T;
--     display period is equal to Disp_T - Fmax.
--^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
library IEEE;
use IEEE.std_logic_1164.all;
entity Taсhometer is
    generic( Fmax: integer:=32);  -- Максимальная частота,
                  --  1 деление=200 об/мин
    port(CLK: in STD_LOGIC;
        RST: in STD_LOGIC;
        DATAI: in STD_LOGIC;
        DATAO: out STD_LOGIC_VECTOR (Fmax-1 downto 0));
end Taсhometer;

architecture Hobby of Taсhometer is
      constant measure_T: integer := 1024;--Максимальный период сигнала,
                                    --тактов, соответствует ~400об/мин
      constant measureMIN:integer := 68; --Минимальный период сигнала,
                                --тактов=1024/15, соответствует ~6000об/мин
    constant Disp_T: integer := 4093;--Период отображения, тактов
    constant Masstab:integer := 1000;--Масштабный коэффициент
    signal DATAId: STD_LOGIC;
    signal Calculate,Measure,Display, Waiting :boolean;--FSM states
    signal CT2:integer range 0 to Disp_T+3;
    signal Period: integer range 0 to measure_T;
    signal M: integer range 0 to measure_T-1;
    signal F: STD_LOGIC_VECTOR(Fmax-1 downto 0);  --F = Masstab/Period

begin
    --DATAI __/^^\___/^^\___/^^\___
    --DATAId __/^^\___/^^\___/^^\___
    --Measure__|^^^^^|_____________________
    --Calculate_________|^^^^^^|_____________
    --Display   __________________|^^^^^^^^^^^|____
    --Waiting  ^^|_______________________________|^^^^

    CNTRL:process(CLK,RST)
    begin
        if RST='1' then
            Calculate<=false;
            Measure<=false;
            Display<=false;
            Waiting<=true;
            CT2<= 0;
        elsif CLK='1' and CLK'event then
            DATAId<=DATAI;    --input delay
    -- finite state machine
            if ( DATAI='1' and DATAId='0' and Waiting ) then
                Measure<= true ;
                Waiting<= false;
            elsif ( DATAI='1' and DATAId='0'and Period>MeasureMIN ) then
                Measure<=false ;
                Calculate<=true;
            elsif(CT2 = Disp_T) then
                Display<=false;
                Waiting<=true;
            elsif (CT2 = Fmax)then
                Calculate<=false;
                Display<=true;
            end if;
    --clock counter
            if ( calculate or display) then
                CT2<= CT2+1;
            elsif  Waiting then
                CT2<= 0;
            end if;
        end if;
    end process;

    CT_PERIOD:     process(CLK,RST) --Счетчик периода вх.импульсов
    begin
        if RST='1' then
            Period<=0;
        elsif CLK='1' and CLK'event then
            if Measure then
                Period<=Period+1;
            elsif Waiting then
                Period<=0;
            end if;
        end if;
    end process;

    AU_FREQ:process(CLK,RST)--вычисление частоты и ее отображение
    begin
        if RST='1' then
            f<=(others=> '0');
            M<=Masstab;
        elsif CLK='1' and CLK'event then
            if  measure then
                M<=Masstab;
                f<=(others=> '0');
            elsif calculate then
                if ( M-Period >0 ) then
                    M<=M-Period ;
                    F<=F(F'left-1 downto 0) & '1';
                            --сдвиговый регистр- столбик
                end if;
            end if;
        end if;
    end process;
    DATAO<=F;
end Hobby;


VHDL

Как работает симулятор

При работе на VHDL программист программирует параллельные операторы, которые выполняются на некоторой виртуальной параллельной вычислительной системе. Нижний уровень программистской модели образует архитектура виртуального процессорного элемента (ВПЭ), который исполняет один параллельный оператор, а верхний уровень - множество ВПЭ, объединенных запрограммированной системой межпроцессорных связей, по которым пересылаются сигналы.

Модель вычислителя с точки зрения программиста не может быть реализована в виде реальной многопроцессорной вычислительной системы из-за чрезмерно высоких аппаратных затрат. С другой стороны, язык VHDL разрабатывался с целью реализации в симуляторах дискретных систем. Собственно, IEEE Standard VHDL Language Reference Manual представляет собой описание синтаксиса конструкций языка и как они должны исполняться в симуляторе. Такой симулятор, как правило, реализован на однопроцессорной ЭВМ. Рассмотрим архитектуру вычислителя VHDL с точки зрения разработчика симулятора.

На рис. условно показана архитектура симулятора VHDL.

В данной модели каждый ВПЭ реализован как отдельный вычислительный процесс (ВП). Все вычислительные процессы разделяют во времени один и тот же аппаратный ресурс - центральный процессорный элемент (ЦПЭ) микропроцессора ПЭВМ.

Все ВП разделены на три подмножества - очередь спящих процессов, очередь готовых процессов и исполняемый процесс. Большинство ВП относится к числу спящих, т.е. к ВП, для исполнения которых нет готовых входных данных. Например, такой ВП ожидает какой-либо входной сигнал, из списка чувствительности его оператора wait. При поступлении сигнала этот ВП переносится в очередь готовых к исполнению ВП. Один из готовых ВП, выбранный произвольно, пересылается в кэш-ОЗУ микропроцессора для исполнения. Исполняемый ВП выполняет свои операторы в соответствии с семантикой функционирования ВПЭ на ресурсах ЦПЭ микропроцессора и алгоритмами соответствующих библиотек процедур. При достижении оператора wait ВП останавливается. Выработанные им сигналы запоминаются и пересылаются другим ВП, которые являются приемниками этих сигналов. Затем данный ВП пересылается в очередь спящих процессов.

Один особенный исполняемый ВП служит диспетчером для остальных процессов. Он называется ядром симулятора и формирует очереди спящих ВП и готовых к исполнению ВП, а также выбирает ВП для исполнения. Он также рассылает сигналы от исполняемого ВП к другим ВП. Кроме того, он ведет счетчик времени моделирования ТС, выполняет связь с консолью, обслуживает обращение к дисковой памяти и памяти глобальных переменных.

Для моделирования программист создает проект – каталог с файлами VHDL, имеющий название проекта. После компиляции в проекте создается библиотека проекта, которая имеет название проекта и содержит все скомпилированные объекты проекта. После запуска программы на моделирование сперва выполняется связывание объектов проекта и назначение начальных значений переменным и сигналам (elaboration).

Затем запускается собственно моделирование. При этом выбранные программистом сигналы записываются в отдельной области памяти в своем развитии и могут быть отображены на дисплее в виде таблиц или графиков.

Для того, чтобы сохранить семантику исполнения множества параллельных процессов, такую же, как у системы из ВПЭ, в каждом цикле моделирования, кроме начального, симулятор выполняет следующие шаги:

  • Каждый остановленный ВП, для которого произошло событие в предыдущем цикле моделирования, которое ожидает соответствующий оператор wait, запускается на исполнение; в ВП, остановленных для ожидания задержки проверяется окончание этой задержки и если задержка истекла, эти ВП также запускаются.
  • Каждый запущенный ВП исполняется до своей остановки на операторе wait, при этом вычисляются новые значения сигналов в операторах присваивания сигналам.
  • Вычисляется новое значение текущего времени ТВ как ближайший момент времени, в который будет запущен какой-либо ВП, остановленный на операторе wait ожидания окончания задержки или момент времени следующей активации источников сигнала.
  • Счетчик времени принимает новое значение ТС = ТВ .
  • Каждому сигналу, для которого было вычислено новое значение, присваивается это значение; эти изменения сигналов проверяются, являются ли они событиями для каких-либо ВП.

Если в следующем цикле моделирования не запускается ВП по окончанию заданной задержки или активация источников сигнала происходит без задержки, то в данном цикле счетчик времени ТС сохраняет свое прежнее значение, измеряемое в фемта- или пикосекундах. В этом случае считается, что время моделирования увеличилось на дельта-задержку.

Моделирование имеет такую особенность, что серия, включающая от нуля до нескольких циклов с дельта-задержкой сменяется одним циклом с конкретной задержкой. Обычно таких циклов в серии 0-10. Если моделируется комбинационная схема из n уровней, каждый из которых задан процессом без задержки, то будет n циклов в серии. Если программа неправильная и зацикливается, тогда циклов в серии будет значительно больше. Так, симулятор Active HDL останавливается, если циклов в цепочке более 1000.

Допустим, что в модели находятся два процесса, обменивающихся одной глобальной переменной. Тогда порядок обмена этой переменной не контролируется программистом, так как он не знает какой из этих процессов сработает первым в серии циклов с дельта-задержкой. Для того, чтобы эти процессы были запущены не в произвольном, а именно в последнем цикле с дельта-задержкой из серии циклов, причем после всех процессов, то такие процессы обозначаются как отложенные, т.е. в программе перед словом process ставится ключевое слово postponed.

При составлении VHDL-программ желательно иметь в виду следующее.

  • Даже небольшой процесс занимает в памяти несколько килобайт. А максимальное количество процессов в скомпилированной программе определяется объемом динамической памяти компьютера.
  • Смена одного ВП другим ВП представляет собой смену контекста в работе ЦПЭ, которая может длиться несколько тысяч тактов. Следовательно, чем меньше процессов и вообще - параллельных операторов - тем быстрее моделирование.
  • Наибольшую долю времени занимает исполнение ВП ядра симулятора, которая возрастает нелинейно с увеличением числа ВП и числа сигналов в списках чувствительности их операторов wait. Поэтому опять же, чем меньше процессов в откомпилированной программе и сигналов в списках чувствительности - тем быстрее выполняется эта программа в симуляторе.
  • Не следует программировать процесс без оператора wait (или без списка чувствительности), т.к. после того, как этот процесс станет активным, он монопольно захватит ресурсы ЦПЭ.

Насколько важно следовать этим рекомендациям? Это дело вкуса. В одной из первых моих VHDL- моделей я вставил модель ПЗУ в виде:

А(0)<= X"12";
…
А(4095)<= X"EF";

И долго удивлялся, почему инициализация модели длилась несколько минут, а модель такого простенького ПЗУ занимала в памяти больше 6 Мбайт. Понимание пришло, когда узнал, что каждой такой строчке соответствует отдельный ВП. При замене массива-сигнала на массив- переменную моделирование существенно ускорилось, а модель ПЗУ стала занимать 0,6 Мбайт. А когда ПЗУ было закодировано константой, то место в ОЗУ для его модели уменьшилось до 0,13 Мбайт и соответственно, ускорилось моделирование.


VHDL

Изучение VHDL. Стиль программирования для синтеза

Одним из важнейших назначений VHDL является описание проектов дискретных устройств для автоматизированного проектирования микросхем. В основе технологии разработки микросхем (заказных СБИС или ПЛИС) лежит автоматическая трансляция VHDL-описания дискретного устройства в схему на логическом уровне, которая выполняется с помощью компилятора-синтезатора. Здесь под синтезом понимается получение аппаратной модели, которая исполняет исходную VHDL-программу и преобразование её в логическую схему. Причем подбор структуры модели, её логическая оптимизация по критериям минимума аппаратуры и максимума быстродействия с учетом элементного базиса целевой микросхемы выполняются автоматически.

Программирование на VHDL означает организацию вычислительного процесса на программистской модели параллельной вычислительной системы, состоящей из виртуальных процессорных элементов (ВПЭ). Например, каждый из таких параллельных операторов, как процесс, параллельное присваивание сигналу, выполняется на таком ВПЭ. А последовательные операторы процесса образуют программу этого ВПЭ .

Работа компилятора-синтезатора основана на взаимно-однозначном инъективном отображении программистской модели, отвечающей исходной VHDL-программе, в аппаратную модель. Это означает, что каждому из виртуальному ВПЭ с его программой ставится в соответствие некоторый специализированный процессорный элемент (СПЭ), а граф линий связи между ВПЭ и граф соединений между СПЭ - изоморфны.

Различают два типа СПЭ: СПЭ с памятью и без неё. СПЭ без памяти представляют собой комбинационную схему, состояние выходов которой (источников сигнала) представляет собой некоторую логическую функцию от состояния её входов (приемников сигнала).

СПЭ с памятью имеют в своей структуре комбинационную схему и регистры для хранения результатов и промежуточных операндов. Состояние выходов СПЭ является логической функцией не только от состояния входов, но и от состояния регистров. Регистры могут запоминать операнды как по уровню синхросигнала (защелка), так и по его фронту (триггер).

В отличие от ВПЭ задержка от входов СПЭ до его выходов представляет собой величину, определяемую по характеристикам элементного базиса, а не дельта-задержку или задержку, заданную оператором wait.

При отображении вместо оператора каждого типа подставляется соответствующая ему логическая схема. Так, операции and ставится в соответствие логическое "И", а операции "*" - комбинационный умножитель.

Если, по ceмантике оператора процесса предполагается, что не вce его переменные и сигналы выполняют присваивания при некотором запуске процесса, то это означает, что такие переменные и сигналы должны хранить свое предыдущее состояние при этом запуске. Поэтому эти процессы отображаются в СПЭ с памятью.

На аппаратную модель реализации VHDL налагается ряд ограничений, свя-зан-ных с особенностями элементной базы СБИС или ПЛИС. Эти ограниче-ния имеют прообраз в программистской модели. В основном, они образуют множество объектов и операторов языка, которые не могут быть отображены в аппаратуру, так как не имеют в ней соответствующего эквивалента.

На ceгодняшний день не могут быть отображены в аппаратуру сигналы и переменные типа с плавающей запятой, динамического типа, файлового типа, операция деления, операторы wait с параметром задержки, операторы вывода на консоль assert и report. Также глобальные переменные не находят своего отображения.

Некоторые значения перечисляемого типа, такие как "U" - не инициализированное, "Х" - неизвестное, "-" - безразличное, также не могут быть отображены в аппаратуру, а другие, как например, "Н" - слабая единица или "L" - слабый ноль, отображаются, соответственно в 1 и 0.

Не могут быть синтезированы такие языковые конструкции, для которых невозможно определить конкретную комбинационную схему на период компи-ля-ции. Например, оператор цикла отображается в многоуровневую комбинаци-он-ную схему, в которой число уровней равно количеству итераций. И если ко-ли-чест-во итераций неизвестно на период компиляции, т.е. это количество не выражено статическим выражением (например, если пара-метр итераций вычисляется в процесce), то такую схему построить невозможно.

Говорят, что VHDL-программа, в которой отсутствуют несинтезируемые объек-ты, операторы и конструкции, написана стилем для синтеза. При составлении программы стилем для синтеза желательно принять во внимание следующее.

»Существует несколько широко распространенных компиляторов-синтезаторов от различных фирм-поставщиков. Эти компиляторы различаются, в частности, списком несинтезируемых элементов языка VHDL. Причем с появлением новых версий компиляторов этот список обычно сокращается.

»Компиляторы-синтезаторы также существенно различаются по возможностям оптимизации отображения, набором атрибутов, управляющих синтезом, библиотеками процедур и функций, возможностями распознавания идиом языка, которые эффективно отображаются в СПЭ, адаптированные к целевой элементной базе. Поэтому для умелого написания программ для синтеза желательно накопить опыт работы с тем или иным компилятором.

Программисты, которые уже ощутили смысл и тонкости синтезируемого стиля, программируют свою собственную программистскую модель. Такая модель является тем самым вычислительным устройством, которое проектируется. При этом естественным образом представляется, как за каждым параллельным оператором стоит аппаратный узел, который исполняет этот оператор.

Например,

С<=A+B;  -- отображается в сумматор;
process(clk) begin
   if rising_edge(clk)  then
          if ena='1';  then
                С<=B;
          end if;
    end if;
end process; -- отображается в регистр с разрешением записи, а
process(clk) begin
   if rising_edge(clk) then
        if ena='1' then
            С<=B+А;
        end if
;
   end if;
end process; -- отображается в тот же сумматор с тем же регистром на выходе.


VHDL

VHDL - FPGA

Что такое FPGA?

Программируемые логические интегральные схемы (ПЛИС) появились полтора десятилетия назад как альтернатива программируемым логическим матрицам (ПЛМ). От последних ПЛИС отличаются как по архитектуре, так и по технологии изготовления.

ПЛМ представляет собой матрицу многовходовых (несколько десятков входов) логических элементов с триггерами, в которых перемычками программируются конституенты единиц дизъюнктивных нормальных форм функций этих элементов. Вначале перемычки выполнялись в виде пережигаемых тонких проводничков. Теперь перемычки выполняются в виде МОП-транзистора с плавающим затвором, т.е. как в электрически перепрограммируемом ПЗУ, т.е. ПЛМ изготовляются по технологии флэш-памяти. Большие ПЛМ (CPLD) отличаются только тем, что несколько ПЛМ собраны на одном кристалле и объединены программируемым полем связей.

ПЛИС представляет собой матрицу маловходовых (от двух до пяти входов) логических элементов, триггеров, отрезков линий связи, соединяемых перемычками из полевых транзисторов. Судя по английскому названию - Field Programmable Gate Array (FPGA) - ПЛИС программируются изменением уровня электрического поля (field) в затворах этих транзисторов. В отличие, например, от LPGA - Laser Programmable Gate Array. Затворы всех "программирующих" полевых транзисторов подключены к выходам триггеров одного длинного сдвигового регистра, который заполняется при программировании ПЛИС. Некоторые из участков этого регистра могут также выполнять роль ячеек ПЗУ.

Прошивка обычно хранится в ПЗУ, стоящем рядом с ПЛИС и после включения питания или по сигналу сброса она автоматически переписывается в программирующий сдвиговый регистр ПЛИС. Этот процесс называется конфигурированием ПЛИС. Так как основу ПЛИС составляют триггеры, хранящие прошивку, то ПЛИС изготавливаются по технологии микросхем статического ОЗУ.

По сравнению с CPLD, ПЛИС выигрывают,

  • во-первых, в неограниченном количестве перепрограммирований,
  • во-вторых, в логической емкости, в том числе в удельной емкости вентилей на цент,
  • в-третьих, в малом энергопотреблении.

Как правило, ПЛИС имеют на два - три порядка большую емкость в числе эквивалентных логических вентилей, чем CPLD и также как статическое ОЗУ, почти не потребляют энергии при отсутствии переключений. Кроме того, у ПЛИС на порядок выше надежность (ниже интенсивность отказов), чем у CPLD.

К недостаткам относят необходимость внешнего ПЗУ прошивки, генератора синхросерии. Но 8-выводовое ПЗУ занимает на плате значительно меньше места, чем сама ПЛИС с многими сотнями выводов. То же касается генератора синхросерии.

Много сомнений у пользователей возникает с защитой проекта от копирования. Действительно, прошивка ПЛИС хранится во внешнем ПЗУ, содержимое которого просто копируется. НО изменить или расшифровать прошивку, например, для скрытия авторства или восстановления схемы, практически невозможно, так как семантика битов в файле прошивки - секрет фирмы, а неосторожное изменение ее может вывести ПЛИС из строя. Если требуется защита, то загрузку программы выполняют с помощью внешней CPLD, автомат в которой обеспечивает защиту проекта. В ПЛИС новых поколений предусматривается шифрование прошивки, например, с помощью встроенного шифрователя DES с обеспечением сохранения ключа с помощью батарейки.

Архитектура ПЛИС фирмы Xilinx

Фирма Xilinx принадлежит к числу родоначальников ПЛИС и самых крупных их производителей. Ниже рассматривается краткое описание архитектурных особенностей ПЛИС серии Virtex выпускаемой этой фирмой. Эти особенности наследуются в новых сериях ПЛИС, а также в серии Spartan, микросхемы которой призваны заменить заказные СБИС в мало- и среднесерийном производстве изделий электроники. Кроме того, принципы функционирования структурных элементов ПЛИС этой серии узнаваемы в архитектурах ПЛИС других фирм-производителей, таких как, Altera, Actel, Atmel.

Топология ПЛИС

На площади кристалла ПЛИС размещены матрица конфигурируемых логических блоков (КЛБ или CLB), матрица отрезков линий межсоединений, покрытых матрицами из полевых транзисторов - перемычек. По краям кристалла размешены блоки настраиваемых ОЗУ - BlockRAM. По периметру кристалла размещены блоки ввода-вывода сигналов (IOBs), а также периферийный канал линий межсоединений, называемый Versaring, предназначеный для соединения КЛБ с произвольным IOB линией связи с малой задержкой.

Логическая таблица

Роль основного логического элемента в ПЛИС играет логическая таблица (ЛТ) или look-up table (LUT), представляющая собой однобитное ОЗУ на 16 ячеек. В ЛТ по адресу G3,G2,G1,G0 записана единица, если код адреса представляет собой конституенту единицы заданной четырехвходовой логической функции. Например, если по адресу 1,1,1,1 записана единица, а по остальным адресам - ноль, то ЛТ реализует четырехвходовую функцию И. На рис. показан пример кодирования функции Исключающее ИЛИ на четыре входа.

Триггеры ЛТ входят в состав программирующего сдвигового регистра и их начальное состояние заполняется в период конфигурирования ПЛИС.

Триггер

В ПЛИС используются программируемые D-триггеры. При конфигурировании можно задать такие режимы работы триггера, как триггер с начальным сбросом (R) или начальной установкой (S), с записью по фронту или спаду синхросерии, с разрешением или без разрешения записи.

После окончания конфигурирования ПЛИС выдает сигнал общего сброса GSR, который устанавливает все триггеры в 0 или 1.

Структура КЛБ

В базовой серии ПЛИС XC4000 фирмы Xilinx основной единицей оборудования считается КЛБ, состоящий из двух триггеров и двух ЛТ. В новых сериях ПЛИС количество триггеров и ЛТ увеличилось вдвое и вчетверо. Чтобы оставить для всех серий одну и ту же единицу оборудования, условились называть КЛБ из двух триггеров и двух ЛТ эквивалентным КЛБ (ЭКЛБ) или CLB slice. Таким образом, КЛБ серии Virtex состоит из двух ЭКЛБ, а серии VirtexII - из четырех ЭКЛБ .

Схемы для ускорения арифметических операций

В ЭКЛБ две ЛТ и два триггера соединены вместе через схему ускоренного переноса и два однобитных полусумматора. Эти схемы позволяют эффективно реализовать многоразрядные параллельные сумматоры, а на их основе - всевозможные счетчики и АЛУ.

Для минимизации оборудования и ускорения вычисления операции умножения используется дополнительная схема поразрядного произведения.

Следует добавить, что в новой серии VirtexII аппаратно реализованы умножители 18 на 18 разрядов.

Мультиплексоры в ПЛИС

Большую долю оборудования в ВС занимают мультиплексоры. С помощью ЛТ можно реализовать двухвходовой мультиплексор. Для эффективной реализации 4-х и более - входовых мультиплексоров в КЛБ имеются схемы мультиплексоров F5 и F6, которые играют роль верхних уровней древовидного мультиплексора. Также они используются для построения функции 5-входовой (F5) и 6-входовой (F6) логики.

Шины с тремя состояниями

Применение шин с тремя состояниями - типичное схемное решение вычислительных устройств, реализованных на плате. Благодаря такому решению, легко достигается многомодульность и наращиваемость системы, низкие аппаратурные затраты и малые задержки в системе межсоединений. Внутри заказных СБИС редко применяются шины с тремя состояниями из-за технологических трудностей их безотказной реализации, а также увеличенной задержки на их переключение.

Несмотря на это, в ПЛИС фирмы Xilinx всё-таки широко применяются шины с тремя состояниями, хотя это существенно повышает их себестоимость. Зато, во-первых, проще выполнить переход от проекта схемы на плате к проекту системы на кристалле. Во-вторых, ВУ с общими шинами, к которым подключено несколько десятков модулей, имеет аппаратные затраты в несколько раз меньше, чем такое же ВУ, в котором шины заменены на эквивалентную схему из системы мультиплексоров. В-третьих, с помощью общих шин эффективно реализовать встроенное распределенное ОЗУ, о котором пойдет речь ниже.

Для реализации общей шины каждый КЛБ имеет два буфера с тремя состояниями BUFT , которые через транзисторы-перемычки могут подключаться к общим шинам, проходящим вдоль всего кристалла. В обычных шинах третье состояние характеризуется уровнем, находящимся между уровнями логической 1 и логического 0. Но если такую шину реализовать внутри микросхемы, то в случае, когда все тристабильные буферы будут в третьем (закрытом) состоянии, их выходные транзисторы будут полуоткрытыми и могут выйти из строя. Для исключения такого электрического режима в ПЛИС общая шина нагружена на концах специальной триггерной схемой - Weak Keeper , которая выводит уровень шины или к уровню H, или к уровню L (слабые 1 или 0), если все буферы закрыты.

Неправильное функционирование общей шины, когда несколько источников с разными уровнями подключаются к шине, может вывести ПЛИС из строя. САПР ПЛИС тсчательно проверяет, чтобы спроектированная общая шина функционировала правильно. Поэтому не рекомендуется ручное редактирование файла прошивки, так как случайная ошибка в коде может привести к неправильной работе общей шины и порче ПЛИС.

ОЗУ в ПЛИС

Для реализации в ПЛИС модулей ОЗУ предусмотрено две возможности. Первую возможность предоставляет каждая ЛТ, которая может быть сконфигурирована как 16-битовое синхронное ОЗУ. Две соседних ЛТ могут быть сконфигурированы как 16-битовое двухпортовое ОЗУ с записью и чтением по одному адресу и чтением по другому адресу, как показано на рис. При этом для реализации синхронного режима записи входной бит данного, сигнал записи и адрес запоминаются в триггерах - защелках, а для чтения по второму адресу из блока второй ЛТ используется только мультиплексор чтения.

Для наращивания емкости памяти выходы нескольких КЛБ с модулями ОЗУ через тристабильные буферы подключаются к общим шинам. При этом требуется дополнительное оборудование только для построения схемы дешифрации адреса, которая выдает сигналы выборки той или иной ЛТ для записи, а также того или другого тристабильного буфера для чтения. Такое ОЗУ распределено по площади кристалла и поэтому названо Distributed RAM.

Если ЛТ запрограммировать как примитив SRL16, то из ее триггеров будет реализован 16-разрядный сдвиговый регистр с однобитовым входом и программируемым номером выходного разряда, т.е. память FIFO регулируемой длины.

Вторую возможность предоставляют отдельные блоки памяти BlockRAM. В ПЛИС серии Virtex они могут быть сконфигурированы как ОЗУ объемом 256 16-разрядных слов, 512 8-разрядных слов, и т.д. Эта память может быть запрограммирована как однопортовая или как полностью двухпортовая память. Начальное состояние этой памяти задается при ее конфигурировании, поэтому она может быть использована также как ПЗУ.

Блоки ввода-вывода сигналов

ПЛИС находят широкое применение благодаря тому, что их можно включать в большинство проектов вычислительных устройств и ими можно заменять большое количество старых микросхем. Предпосылкой этому служит большое число блоков ввода-вывода сигналов IOB, настраиваемых под различные стандарты электрического соединения входов микросхем. На рис. показана структура одного IOB.

Сигнальный вывод ПЛИС получил название PAD. С помощью настройки к нему можно подключать внутренний нагрузочный резистор PULLUP или резистор PULLDOWN, соединенные с шиной питания или шиной земли, соответственно. Эти резисторы обеспечивают режим выхода с открытым коллектором (стоком) для систем с различными уровнями логики. Входной сигнал с PAD поступает на компаратор IBUF, порог срабатывания которого программируется под уровни ТТЛ, КМОП, шины PCI и многие другие, а также может регулироваться установкой подаваемого снаружи напряжения. Для обеспечения временного сдвига сигнала относительно фронта синхросерии, обеспечивающего надежный прием сигнала во внутренние триггеры, в цепь входного сигнала может включаться специальная схема задержки.

Выходной сигнал в IOB формируется в тристабильном буфере OBUFT, причем его уровень максимального тока программируется ступенями и может достигать 20 мА. Для обеспечения быстродействующего ввода-вывода передаваемые и принимаемые биты данных, а также сигнал управления тристабильным буфером могут запоминаться в триггерах.

В новых сериях ПЛИС предусмотрена настройка входного и выходного импеданса PADа, а также бифазное функционирование пар PADов для достижения помехоустойчивой высокоскоростной передачи данных.

При диагностике и отладке, в одном из режимов конфигурирования ПЛИС может быть переключена в режим пограничного сканирования (Boundary Scan). В этом режиме все IOB соединяются в цепочку одного длинного регистра сдвига. Путем стандартного внешнего управления этим регистром сдвига через интерфейс JTAG можно считывать состояния выводов, подавать тестовые сигналы, конфигурировать ПЛИС.

В период конфигурирования ПЛИС для того, чтобы подключаемые к ней устройства не функционировали неопределенным образом, выходы IOB отключаются и на них обычно выставляется уровень H слабой единицы (Weak Keeper).

Система синхронизации

Одним из принципов разработки проектов для ПЛИС является принцип однотактной синхронизации, согласно которому все триггеры в блоке срабатывают одновременно по одному сигналу синхросерии. Для его реализации в ПЛИС синхросигналы распространяются по быстродействующей древоообразной сети, которая обеспечивает почти одновременных приход фронта синхроимпульса на синхровходы всех триггеров.

Для надежного функционирования ПЛИС синхросигнал должен подаваться через вывод GCLKPAD и попадать в сеть синхросерии через буфер GCLKBUF. В ПЛИС предусмотрено 4 вывода GCLKPAD, размещенных на противоположных сторонах ее корпуса. Синхросигнал может вырабатываться и внутри ПЛИС, но в этом случае его следует завести в сеть синхросерии через глобальный буфер BUFG.

С помощью спроектированного синхронного автомата, сконфигурированного в ПЛИС, можно изменять частоту и фазу синхросерии. Но в этом случае ее временные параметры будут недостаточно стабильными и поэтому такой подход обычно не применяется. Для надежного регулирования частоты синхросерии в ПЛИС включают делители частоты синхросерии с автоподстройкой - блоки CLKDLL. На рис. показана типичная схема его включения. Блок CLKDLL обеспечивает умножение частоты синхросерии в 2 раза, сдвиг ее фазы на 90, 180 и 270 градусов, деление на 1.5, 2, 2.5, 3, 4.5, 8 и 16.

Конфигурирование ПЛИС

Для конфигурирования ПЛИС в ней предусмотрены входы задания режима M2, M1, M0, вывод синхросерии программирования CCLK, вход последовательности конфигурации PROGRAM, выход флага окончания конфигурирования DONE и выводы порта JTAG. В зависимости от установленного режима можно загружать прошивку ПЛИС через однобитовый вход PROGRAM, порт JTAG или 8-разрядную шину D c использованием для управления выводов WRITE и BUSY.

Конфигурирование через однобитовый вход длится до нескольких десятков секунд. Это стандартный способ конфигурирования и для него не требуется дополнительного оборудования, кроме ПЗУ прошивки с однобитовым выходом.

Для реализации конфигурирования через шину D необходимо дополнительное внешнее устройство (автомат или микроконтроллер), управляющее записью и выдающее последовательность адресов чтения на входы байтового ПЗУ. Зато оно происходит значительно быстрее - практически с максимальным темпом чтения из ПЗУ.

Разработка систем на кристалле (СНК) - это устойчивая современная тенденция. И программирование ПЛИС для СНК - один из этапов главных такой разработки. Выпуск ПЛИС новых поколений, например, Xilinx VirtexPro, направлен на поддержку развития СНК. Разработка СНК без применения языка VHDL или Verilog практически невозможна.


VHDL

Литералы

Где-то треть жителей планеты говорит на английском языке. Из них около половины не знают английского языка. Например, чтоб разговаривать на пиджин-инглиш, достаточно иметь словарный запас 200-300 слов. Естественно, на таком диалекте произведений не пишут. Приблизительно то же самое можно сказать и о пишущих на VHDL. Но для конструирования произведений с помощью VHDL нужно хотя бы знать синтаксис языка. Данная страничка и несколько других этому посвящаются.

В языке литералом задается такой лексический элемент, который при компиляции кодируется некоторым числовым кодом, который остается постоянным в программе при ее исполнении. Константы, операнды в выражениях, идентификаторы представляются литералами. То, что синтаксис литерала отображает признак типа соответствующего ему объекта, является одной из особенностей VHDL.

Числовой литерал представляет собой целое или вещественное число.

Десятичный литерал - это числовой литерал в системе счисления по основанию (базису) 10, например, 120.

Вещественный литерал отличает обязательное наличие точки, отделяющей целую часть от дробной, например, 120.0, 1.20е2.

Базисный литерал - это число в системе счисления с заданным базисом от 0 до 16. Его условный синтаксис:

\базисный литерал\::=\базис\#\число в базисе\#[\экспонента\]

Напоминание: при описаниие синтаксиса текст в квадратных скобках означает необязательный элемент. Например, 10#112# = 16#70# = 2#1110000# = 2#111#e4. Можно также применять базис и 3, и 4, и 5…

. Какой ещё язык предоставляет такую возможность?!

Символьный литерал используется как значение для операторов или как элемент перечисляемого типа, например, бит. Он записывается как символ в одиночных кавычках, например, '1', 'F' , '@'.

Идентификатор. Идентификатор используется как имя константы, переменной, функции, сигнала, порта, подпрограммы, объекта проекта, а также как метка. Он содержит латинские буквы, с которых он начинается, цифры и некоторые символы, например, однократный символ подчеркивания. Идентификаторы с одинаковым названием но с различными заглавными и строчными буквами считаются одним идентификатором, т.е. они "нечувствительны" к высоте букв. Ключевое слово языка не может быть идентификатором.

Идентификатор может состоять из произвольной цепочки символов, но эта цепочка должна быть заключена между обратными косыми. Это так называемый, расширенный идентификатор. Например:

C, A_and_B, \наш сигнал\, \а+в\, \process\

являются корректными идентификаторами.

Перечисляемый литерал. К перечисляемым литералам относятся символьный литерал и идентификатор. Из этих литералов формируется множество перечисляемого типа.

Строчный литерал. Строчным литералом является цепочка символов, заключенная в двойные кавычки, например, "АБВГ". Литерал битовой строки может иметь различный вид в зависимости от базиса системы счисления. Например, литералы "01111010", В"01111010", Х"7А" представляют собой одно и то же значение, причем В и Х означают двоичный и шестнадцатиричный базисы, соответственно.

В числовых литералах и битовых строках допускается вставлять символы подчеркивания для удобства чтения, которые удаляются при компиляции.

Например, Х"АВ_CD", "1101_0111", 1_024, 0FF_ABBA .


VHDL

Типы

Сигналы, переменные, константы и другие объекты языка VHDL служат для хранения некоторых значений. Эти значения могут быть присвоены объектам в одном месте и затем использованы в другом месте программы, как операнды в выражениях, функциях и т.п. Прежде чем остановиться на описании объектов, необходимо рассмотреть типы объектов. Не путать с объектом проекта - собственно, программой, описывающей интерфейс и алгоритм функционирования некоторой единицы проекта.

Тип - это множество значений с общим признаком. VHDL - строго типизированный язык. Каждый объект объявляется со своим типом и может присваивать значение только данного типа. Соблюдение правил присваивания объектов и соответствия их типов требует дополнительных усилий программиста. Но благодаря этой особенности, программы VHDL имеют высокую надежность и обеспечивают экономию времени при отладке.

Перечисляемый тип определяется как список (перечисление) всех возможных значений данного типа. Объявления этого типа выглядит как:

type \имя типа\ is (\перечисляемый литерал\
                              {,\ перечисляемый литерал\});

Здесь текст в фигурных скобках может повторяться 0,1,2,… раз.

Элементы списка литералов нумеруются при компиляции слева - направо, начиная с нуля. Например, объявление
type \направление\ is (\налево\,\прямо\,\направо\);

означает, что состояния идентификатора \направление\ будут кодироваться так, что \налево\ соответствует 0, \направо\ - 2.

Целый тип. Объявление этого типа выглядит как:
type \имя типа\ is range \диапазон целых\;

где \диапазон целых\::=\выражение\ to\выражение\
|\выражение\downto\выражение\ .

Выражение целого типа в диапазоне должно быть вычислимо в период компиляции. Максимальный диапазон целых задается как:
-2147483647 to 2147483647.

Тип с плавающей запятой определяется аналогично целому типу, но с ди-а-па-зо-ном с плавающей запятой. Максимальный диапазон зависит от компилятора.

Регулярный тип представляет собой множество элементов одинакового типа. Различают неограниченные и ограниченные регулярные типы. Неограниченный тип объявляется как:

type \имя регулярного типа\ is
       array (\имя типа диапазона\range<>) of \имя типа элемента\;
где \имя типа диапазона\ - имя типа integer или какого-либо подтипа от integer.

Ограниченный регулярный тип объявляется как:

type \имя регулярного типа\ is
        array (\диапазон целых\ of \имя типа элемента\);

Неограниченный регулярный тип применяют тогда, когда заранее неизвестен диапазон типа, например, в процедуре. Но на период компиляции или в момент исполнения программы диапазон объекта этого типа должен быть определен, например, при вызове процедуры с конкретным операндом.

Представителя одномерного регулярного типа обычно называют вектором. VHDL допускает многомерные регулярные типы или многомерные массивы. В их определениях диапазоны индексов перечисляются через запятую, например:
type matrix is array (integer range <>, integer range <>) of integer.

Комбинированный тип определяет множество значений, как и регулярный тип, но эти значения могут быть разнотипными. Объявление комбинированного типа выглядит как:

type \имя комбинированного типа\ is record
       \имя элемента\:\тип элемента\;
       {\имя элемента\:\тип элемента\;}
end record[\имя комбинированного типа\];

Физический тип представляется целым числом, единица которого имеет вес единицы измерения некоторой физической величины. Наиболее распространенным физическим типом в VHDL является время tіme, которое измеряется в фемтосекундах (fs), пикосекундах (ps), наносекундах (ns) и т.д. Объекты физического типа, как правило, не синтезируются, но они могут участвовать как операнды в вычислениях констант других типов.

Другие типы объектов.

Особенными типами являются тип ссылки (access) и тип файла (file). Тип ссылки позволяет манипулировать с массивами переменных, объем которых заранее неизвестен и которые создаются, дополняются и ликвидируются динамически во время вычислений. Тип файла обеспечивает доступ к файлам, записанным в дисковой памяти. Его применяют для ввода-вывода исходных данных и результатов вычислений.

Подтип.

Подтипом называется тип с дополнительными ограничениями. Объявление подтипа имеет следующий упрощенный синтаксис:
\подтип\::=subtype \имя подтипа\ is \базовый тип\ [\ограничение\];

Здесь \ограничение\ - диапазон или подмножество, в зависимости от базового типа. Подтип используют для отождествления группы объектов. С помощью подтипа можно обозначить группу объектов с особенными свойствами, чтобы потом было легче разбираться в программе. Ограничение подтипа позволяет выявить ошибки на этапе моделирования. Объекты разных подтипов, у которых один родоначальный, базовый тип, могут участвовать в вычислених без конфликтов типов.

Предопределенные типы данных.

Основные типы данных VHDL определены в пакете STANDARD, который подключается к проекту по умолчанию. Вот так в нем определены некоторые стандартные типы объектов:

type boolean is (false, true);
type bit is ('0', '1');
type integer is range -2147483647 to  2147483647;
subtype natural is integer range 0 to  2147483647;
type bit_vector is array (natural range <>) of bit;

Следует заметить, что тип integer покрывает все значения, представляемые 32-битовыми словами, кроме одного: -231 .

Также определены подтип positive, включающий положительные значения типа integer, тип character, как набор букв, цифр и знаков, включая буквы альтернативного алфавита,тип string, как одномерный регулярный тип из элементов типа character.


VHDL

Oбъекты языка VHDL

Сигналы, переменные, константы и другие объекты языка VHDL служат для содержания и переноса некоторых значений. Эти значения могут быть присвоены объектам в одном месте и затем использованы в другом месте программы, как операнды в выражениях, функциях и т.п. На данной страничке приведены объекты языка и синтаксис их объявления (декларации).

Сигнал.

Сигналом является объект, который переносит значение от одного процесса к другому и вместе с ним - синхронизирующее воздействие. Сигнал может быть запомнен в своей истории и воспроизведен в симуляторе в виде графика или таблицы. Объявление сигнала выглядит как:

signal : \идентификатор\{,\идентификатор\}:=[\начальное значение\];
где - \начальное значение\ - выражение, представляющее константу, значение которой принимает сигнал перед первым запуском процесса.

Константа.

Константой является объект, не изменяющий свое значение при вычислениях. После объявления константы присваивание ей значения запрещено (кроме случая отложенной константы). Пример объявления константы:
сonstant thousand: integer:=1000;

Переменная.

Переменной является объект, хранящий значение в пределах операторов процесса, функции или процедуры. В отличие от сигнала, присваивание переменной выполняется немедленно. Упрощенный синтаксис объявления переменной:
\объявление переменной\::=
[shared] variable \идентификатор\{,\идентификатор\}:\тип\[:=\начальное значение\];

Пример объявления переменной:
variable tmp: integer range -128 to 127:=0;

Порт.

В структуре программы VHDL выделяются объекты проекта, называемые entity. Не путать объекты языка с объектом проекта. Это связано с тем, что, во-первых, object и entity переводятся одинаково, во-вторых, в Language Reference Manual сигналы, переменные и др. в некоторых декларативных местах обзываются как entities. В этом слове есть что-то философское, как в афоризме: "Электрон неисчерпаем, как и атом".

Порт представляет собой интерфейсный сигнал объекта проекта. Как и в декларации сигнала, в декларации порта указывается его идентификатор, тип, начальное значение. Дополнительно указывается режим работы: in - прием, out - передача, inout - прием и передача, buffer - передача и использование как сигнал-операнд внутри объекта проекта и link – двунаправленное соединение с другим портом с таким же режимом. Упрощенный синтаксис объявления портов объекта проекта следующий:

\объявление портов\::=port (\объявление порта\
                                                {; \объявление порта\});
 \объявление порта\::=\идентификатор\: in |out|inout|buffer|link \тип\ [:=\начальное значение\]

Настроечная константа generic.

Настроечная константа generic кодирует определенное свойство объекта проекта. Она используется, например, для задания разрядности линий связи, кодирования структуры моделируемого устройства. Упрощенный синтаксис объявления настроечных констант следующий:

\объявление настроечных констант\::= generic( \объявление настроечной константы\
                                                      {; \объявление настроечной константы\});
\объявление настроечной константы\::= \идентификатор\:\тип\[:=\начальное значение\]

Переменная цикла.

Переменная цикла - это специальный объект в том смысле, что он не требует объявления. Подробнее о ней сказано при описании оператора цикла loop.

Начальное значение объекта.

Начальное значение объекта в его объявлении - это то значение которое принимает объект перед первым циклом моделирования. Если начальное значение не присвоено, то симулятор присваивает наименьшее значение данного типа, если тип - числовой или самое левое значение, если тип - перечисляемый.

Например, многие вначале удивляются, почему проект, написаный с сигналами стандартного типа STD_LOGIC, отказывается вести себя как задумано - на всех выходах модели - значение U (не инициализировано). Объяснение простое: U - это самое левое значение перечисляемого типа STD_LOGIC, а каким-то сигналам в модели не дали ожидаемого начального значения или на них не распространился сигнал сброса. И значение U распространилось до выходов модели в согласии с логикой STD_LOGIC.

Начальное значение может быть выражением. Но значение выражения должно быть вычисленным до момента трансляции данного объявления. Например, первое объявление:
signal bb:bit:=aa;
signal aa:bit :='1';

неверно, так как при его рассмотрении компилятор еще не имеет сведений о идентификаторе аа.

В аппаратной модели вычислителя VHDL начальное значение объекта эквивалентно состоянию триггеров и шин сразу после включения питания до прихода сигналов сброса, т.е. оно не определено. Поэтому компиляторы – синтезаторы не допускают или игнорируют начальные значения всех объектов, кроме констант или объектов, которые не изменяют свое значение при вычислениях.


VHDL

Операции в выражениях

В VHDL выражения выполняют арифметические или логические вычис-ле-ния над одним или несколькими операндами. Выражения используются в операторах присваивания сигналу, переменной, при присваивании начального значения, как операнд в других операторах, как входной параметр вызова процедуры или функции.

Операции VHDL перечислены в таблице 1 в порядке их приоритета.

Таблица 1 - Операции VHDL.

Тип операции | Символ или ключевое слово
Логические Сравнения Сдвига Сложения Унарные (знак) Умножения Различные | and, or, nand, nor, xor, xnor =, /=, <, <=, >, >= sll, srl, sla, sra, rol, ror +, -, & (конкатенация) +, - *, /, mod, rem **, abs, not

Логические операции имеют самый низкий приоритет. Операнды логических операций должны быть одного типа bit или boolean, или одномерного регулярного типа (векторы) из элементов типа bit или boolean. Для однозначной компиляции логических выражений необходимо использовать скобки, например:
(a or b) and C and (d or c).

Операции сравнения выполняются над операндами одинакового типа и возвращают тип boolean. Операции равенства "=" и неравенства "/=" выполняются над всеми типами. Остальные операции сравнения выполняются над перечисляемыми типами, целыми типами и одномерными регулярными типами (векторами) из элементов такого типа.

Операции сравнения выполняются над операндами одинакового типа и возвращают тип boolean.

Операции равенства "=" и неравенства "/=" выполняются над всеми типами. Остальные операции сравнения выполняются над перечисляемыми типами, целыми типами и одномерными регулярными типами (векторами) из элементов такого типа.

При сравнении перечисляемых типов элемент, стоящий в ряду правее (старший), считается бо'льшим. При сравнении векторов сравниваются пары элементов векторов, начиная с самых левых. Если пара элементов неодинакова, то вектор с более старшим элементом считается бо'льшим. Если пара элементов одинакова то рассматривается следующая пара элементов. Например, в сравнении векторов битов "0111" >="01011" результат будет true.

Операции сдвига выполняют сдвиг вектора битов на число разрядов типа integer. Например, результатом выражения ("100110" sra 3) является вектор "111100" , т.е. происходит арифметический сдвиг вправо на 3 разряда.

Операции сложения - вычитания "+", "-" предопределены для целых чисел и чисел с плавающей запятой. Операция конкатенции "&" применяется со всеми одномерными регулярными типами или с их элементами. С помощью этой операции векторы - операнды объединяются в более длинные векторы. Например, выражение "101" & '1' & "10" даст результат "101110".

Унарные операторы применяются к одиночным операндам. Оператор ми-нус инвертирует значение операнда. Операторы умножения "*", деления "/" приме-ня-ют-ся с целыми операндами и операндами с плавающей запятой. Операторы mod (модуль), rem (остаток) применяются с целыми числами. Операции абсолютного значения abs и возведения в степень "**" определены для целых чисел и чисел с плавающей запятой, причем показатель степени должен быть целым.

Для многих операций языка существуют функции с таким же обозначением. Эти функции выполняют аналогичные действия, что и операции, но над другими типами. Например, функция "+" из пакета numeric_bit библиотеки IEEE выполняет сложение векторов битов, которые кодируют целые числа. Такие функции перезагружают операции в зависимости от типа операндов.

При программировании для синтеза следует учесть, что правый операнд для операций "/", mod, rem может быть равным только степени двойки, а левый операнд операции "**" должен быть равен 2, так что эти операции будут означать сдвиг двоичного кода.

Для большинства операций найдутся эквивалентные функции с таким же названием, определеные в таких стандартных пакетах, как IEEE.std_arith, IEEE.numeric_std. Основным свойством этих функций является то, что они подставляются вместо операций (перезагружают их), если операнды имеют тип integer, а также std_logic_vector, signed, unsigned и другие типы, производные от std_ulogic.


VHDL

Операнды в выражениях.

В VHDL выражения выполняют арифметические или логические вычис-ле-ния над одним или несколькими операндами. Выражения используются в операторах присваивания сигналу, переменной, при присваивании начального значения, как операнд в других операторах, как входной параметр вызова процедуры или функции.

Простейшими операндами являются литерал и идентификатор, такой как имя сигнала или переменной. Само выражение может быть операндом, если его окружить круглыми скобками. Операндами могут быть также агрегат, атрибут, вызов функции, имя с индексом, квалифицированное имя, значение комбинированного типа и его поля, вырезка регулярного типа, функция преобразования типа. Далее подробно рассматриваются эти виды операндов.

Простое выражение чаще всего представляет собой имя объекта со знаком +,- или без него. Для многих операторов операнды должны быть простыми выражениями. Особенно это касается стиля программ для синтеза.

Агрегат. Агрегатом называется операция, которая объединяет одно или несколько значений в значение составного типа, т.е. регулярного или комбинированного типа. Его упрощенный синтаксис:
\агрегат\::=(\связывание элементов\ {,\связывание элементов\})
\связывание элементов\::=[\альтернативы\ =>] \выражение\
\альтернативы\::=\альтернатива\ {,\ альтернатива\}
\альтернатива\::=\простое выражение\|\диапазон\|\имя элемента\| others .

Связывание элементов означает подстановку одного выражения в одно или несколько заданных полей или элементов значений составного типа. Связывание элементов может происходить в порядке нумерации элементов cсоставного типа. Тогда оно называется позиционированным связыванием. Например, в объявлении:
variable v_5: bit_vector (0 to 4):=('0', '0', '0', '1', '1');
битам 0, 1 и 2 присвоено начальное значение 0, а битам 2,3 - значение 1. Если каждый элемент связывается со своим значением по имени, то такое связывание называется поименованным. Например, для той же переменной v_5:
(3 |4 => '1' , others => '0'); или (0 to 2 => '0'; 3 to 4 => '1');

Здесь ключевое слово others означает остальные элементы значения и должно стоять последним в списке связываний. Возможны и комбинированные агрегаты, в которых первые представляют собой позиционное связывание, а остальные поименованное связывание, например,
('0', '0',3 to 4 => '1' , others => '0').

Такая альтернатива, как простое выражение, применяется только для регулярных типов и должна определять номер элемента из диапазона этого типа, например, агрегат (i => '1', others => '0') задает вектор в котором на i-м месте стоит 1, а остальные биты - нулевые.

Альтернатива \имя элемента\ применяется только для комбинированных типов, например:

type complex is record
               (  Re : integer;   Im : integer );
end record;
variable X is complex:=(Re => 1000, Im => 0);

Атрибут. У объектов языка имеется некоторое множество свойств и особенных значений. Атрибут объекта - это специальная функция, которая возвращает его особенное значение. Например, атрибут object1'left возвращает значение самого левого элемента объекта object1 перечисляемого типа. Подробнее об атрибутах будет рассмотрено в разделе, посвященном атрибутам.

Вызов функции. При вызове функции выполняется функция с заданными значениями параметров. Упрощенный синтасис вызова функции:

\вызов функции\::=\имя функции\ ([\имя параметра =>\] \выражение\
                                   {,[\имя параметра\ => ] \выражение\});

где \имя функции\ - имя функции, определяемой ранее, \имя параметра\ - не обязательный формальный параметр этой функции. Выражение - параметр функции - должно давать результат типа, соответствующий имени параметра. Параметры можно задавать с поименованным или позиционированным связыванием. При позиционированном связывании параметры-выражения подставляются в порядке, определенном порядком следования имен параметров в определении функции. При поименованном связывании каждое имя, параметра связывается с соответствующим параметром с помощью символов "=>", причем порядок следования параметров может быть произвольным.

Например, в пакете IEEE.Math_Real определена функция синуса:
function SIN (X : in REAL ) return REAL;
Ее вызов по аргументу вещественного типа выглядит как:
SIN(X=>MATH_2_PI* angle) или SIN(MATH_2_PI *angle) ,
где MATH_2_PI – константа, равная 2π, определенная в этом пакете.

Имя с индексом дает значение элемента регулярного ти-па, номер которого задается выражением в скобках. Например, vect(4) означает 4-й бит вектора vect, arr(i, j) означает элемент (i, j) двумерного массива arr.

Квалифицированное выражение. Результат выражения может принадле-жать нескольким типам одновременно. Если необходимо, чтобы этот результат принадлежал к конкретному типу, то его необходимо обозначить как квалифицированный с заданным типом. Синтаксис такого выражения:
\квалифицированное выражение\::=\имя типа\'(\выражение\)
Например, если объявлено
type vect is bit_vector(0 to 9); var X: vect;
то выражение ('1', others => '0') может принадлежать к типу векторов любой длины. Поэтому для присваивания переменной этого выражения необходимо сделать его квалифицированным:
X:=vect'('1', others => '0');
Имя-вырезка задает цепочку элементов объекта регулярного типа. Его упрощенный синтаксис:
\имя-вырезка\::=\имя\(\выражение\ to | downto \выражение\)
\выражение\ - должно вычислять значение, не превосходящее диапазон индексов объекта регулярного типа с именем \имя\. Направление изменения индекса to или downto должно совпадать с направлением, заданным в объявлении типа. Например, если объявлен сигнал:
signal A: bit_vector(15 downto 0);
то A(15 downto 8) - старший байт сигнала А.

Поле комбинированного типа. Чтобы оперировать с полем объекта комбинированного типа его вставляют в выражение согласно синтаксису:
\поле комбинированного типа\::=\имя комбинированного типа\.\имя поля\
где \имя поля\ - может представлять поле любого типа, а также его имя с индексом, имя - вырезку, агрегат. Например, если объявлены тип и сигнал:

type comp_vect is record
                       (Re: bit_vector(0 to 15); Im:bit_vector(0 to 15));
          end record;
signal A: comp_vect;
 то A.Re(0 to 7) - старший байт поля Re сигнала A типа cоmp_vect.

Преобразование типа. Так как в VHDL присваивание значения объекту требует строгого соответствия типов, то в случае, если типы объектов не совпадают, необходимо выполнить преобразование типа. Его синтаксис соответствует синтаксису вызова функций с одним аргументом.

Различают два вида преобразования типа: переход типа и вызов функции преобразования типа. Переход типа применяется для преобразования тесно связанных типов или подтипов. Такими парами типов являются, например, real и integer, integer и natural, регулярные типы с одинаковым числом элементов того же самого типа с одинаковыми диапазонами индексов. Например, при переходе из значения с плавающей запятой к целому значению:
С:=integer (123.5);
результат С округляется до ближайшего целого, т.е. до 124.

Если типы не тесно связанные, то необходимо выполнить вызов функции пре-обра-зо-ва-ния типа. Например, типы boolean и bit - не тесно связанные т.к. при-над-ле-жат к перечисляемым типам с различными множествами элементов. По-это-му, например, преобразование переменной Х типа boolean в переменную Y типа bit может выполняться функцией преобразования типов, которая включает оператор:
if Х then Y:='1'; else Y:='0'; end if;

Часто программисты пользуются своими функциями преобразования типов. Большинство стандартных и коммерческих библиотек содержат наборы функций преобразования типов.


VHDL

Реализация выражения в аппаратной модели VHDL

Если выражение не упрощается при компиляции до константы или другого объекта, то оно реализуется в аппаратной модели в виде логических комбинационных схем. Операции в выражениях отображаются в схемы, выполняющие эти операции над операндами соответствующих типов.

Логические операции реализуются в соответствующих элементах: and - в элементе "И", not - элементе "НЕ" и т.д. При операциях над битовыми или булевскими данными реализуются одиночные логические элементы. При выполнении операции над операндами регулярного типа каждому элементу операнда ставится в соответствие один логический элемент.

Операции равенства и неравенства реализуются с помощью соответствующего числа элементов "И" с объединением их выходов в элементе "ИЛИ". Операции "больше" или "больше или равно" выполняются с помощью многоразрядной схемы сумматора-вычитателя, выход переполнения которой соответствует булевскому результату этой операции.

Операции, сложения, вычитания, изменения знака выполняются с помощью схемы сумматора, а операция умножения - с помощью комбинационного умножителя. При этом если операнды типа positive, то умножение выполняется на умножителе без учета знака, а если типа integer - на умножителе со знаком.

Операция абсолютного значения abs выполняется на схеме получения положительного числа из отрицательного и мультиплексора, который в зависимости от знака числа пропускает результат на выход схемы.

Операция деления, модуля, остатка и возведения в степень, которые соответствуют сдвигу объекта, представленного двоичным числом, реализуются в схеме сдвигателя. При этом, если операнд типа integer, то сдвиг вправо реализуется с учетом знака.

Операция конкатенации пары операндов регулярного типа соответствует объединению двух шин, пересылающих эти операнды, в одну, состоящую из исходных шин.

При выполнении операций сложения и вычитания разрядность результата дол-ж-на быть равна максимальной разрядности операндов. Операнды операции ум-но-же-ния должны иметь суммарную разрядность, равную разрядности произведения.

Если операнды объявлены как тип integer без диапазона, то им соответствуют 32-разрядные типы и соответствующие 32-разрядные схемы реализации операций. Для минимизации оборудования рекомендуется принять объявление переменной с диапазоном: например, если переменные объявлены как :
variable a, b: integer range (-128 to 127);
то выражение a+b выполняется на 8-разрядном сумматоре.

Сложное выражение от нескольких операндов при отсутствии скобок и с равноприоритетными операциями выполняется последовательно слева направо. Ему соответствует схема из цепочки модулей, выполняющих эти операции. Вставка скобок в это выражение задает приоритет выполнения операций, который отображается в аппаратную схему. Благодаря этому результирующая схема имеет вид дерева из модулей, задержка логических схем которого может быть намного меньше, чем в исходной схеме. На рис. показаны аппаратные схемы, соответствующие выражениям a+b+c+d и (a+b)+(c+d).

">

Вставка скобок в выражение является одним из способов управления ходом синтеза, выполняемого компилятором-синтезатором.


VHDL

Статические выражения

Структура виртуальной параллельной вычислительной системы и ее параметры формируются при компиляции программы VHDL и остаются неизменными в процессе ее исполнения. Точнее, это происходит на последнем этапе – этапе связывания объектов (elaboration). В программах часто встречаются выражения, от результатов которых зависят структура и параметры системы. Это например, настроечные переменные (generic), определяющие порядок включения блоков, их разрядность. Результаты этих выражений должны иметь конкретные значения перед исполнением программы и не должны зависеть от входных данных. Такие выражение получили название статических. Другими словами, непосредственно перед моделированием статическое выражение должно быть вычислено до константы или приведено к идентификатору . Некоторые операторы, например, case, вставки компонента, требуют, чтобы в них входили статические выражения. Например, если объявлены сигналы
signal n: integer;
signal A: bit_vector(16 downto n+1);
то на момент начала моделирования операнд n неизвестен и симулятор будет пытаться подставить n= -2147483647, что вызывает аварийную остановку симулятора при размещении сигнала А в памяти, т.е. здесь выражение n+1 – не статическое.

Если симулятор дает широкие возможности исполнения программы, обеспечиваемые большими ресурсами памяти компьютера и последовательным исполнением операторов, то при аппаратной реализации программы эти возможности значительно уже. Поэтому если программа предназначена для синтеза, то требования применения статических выражений встречаются значительно чаще.

В предыдущем примере симулятор может работать, если у сигнала n было задано начальное нулевое значение. Но для синтеза такая программа не годится, так как, во-первых, присваивание начального значения при синтезе игнорируется или запрещается, во-вторых, в аппаратуре должны быть четко заданы разрядность регистров и шин, объем памяти.


VHDL

Последовательный оператор присваивания

Последовательные операторы в VHDL вставляются в операторы процессов и исполняются последовательно в виртуальных процессорных элементах программистской модели. Последовательный оператор присваивания выполняет присваива-ние переменной или сигналу результата выражения. Он выглядит следующим образом:
\приемник\:=\выражение\ - для присваивания переменной
\приемник\ <= \выражение\ - для присваивания сигнала.

Здесь результат \приемник\ может быть имя (идентификатор), например, var, имя с индексом, как var(1), вырезка, как var (0 to 1), поле, как rec.var или агрегат, как (Re, Im).

Присваивание переменной отличается от присваивания сигналу. Присваивание переменной выполняется немедленно.

Выполнение оператора присваивания сигналу означает вычисление его выражения и лишь назначение сигналу. Само же присваивание сигналу фактически выполняется в момент остановки процесса по ожиданию события. Поэтому если в одном процессе стоит несколько присваиваний одному сигналу, то истинное присваивание происходит в момент остановки процесса. Если перед остановкой процесса выполнялось чтение этого сигнала (участие его в качестве операнда в выражении) то будет прочитано значение, присвоенное в прошлом запуске процесса.

При присваивании части элементов сигнала составного типа или перечисляемого типа, например, имени с индексом, вырезке считается, что выполнено присваивание всем элементам сигнала, причем те элементы, которые не указаны в операции присваивания, принимают старое значение. Например, по фрагменту программы
signal d:bit_vector(0 to 7);
………….. d <= (others => '0');
d(0 to 3) <= "0011";
d(4 to 5) <= "11";M
wait …
сигналу d будет присвоено значение "00111100".

Всем операторам присваивания сигналу в одном процессе в модели виртуального процессорного элемента соответствует один источник сигнала. Если одному и тому же сигналу выполняется присваивание в различных про-цес-сах, то несколько источников сигналов соединяются своими выходами и в общем слу-чае, результирующий сигнал может быть неопределенным. Поэтому над та-ким сигналом должна быть задана функция разрешения, которая разрешает кон-фликт присваивания одному сигналу значений из нескольких источников сигнала.

Если пользоваться пакетом IEEE.STD_LOGIC_1164, то сигнал, объявленный как std_logic, можно присваивать в разных процессах, так как в этом пакете есть функция разрешения для такого типа сигналов.

Присваивание сигналу при моделировании.

При моделировании дискретных систем важное место звнимает моделирование распространения сигнала с учетом задержки в проводниках или задержки в вентилях. Для этого используют следующий расширенный синтаксис присваивания сигналу:

\присваивание сигналу\::=\приемник\ <= [\способ задержки\] \график\;
\способ задержки\::= transport |[reject \выражение времени\] inertial
\график\::= \выражение\ [after \выражение времени\]
                  {, \выражение\ [after \выражение времени\] }

Здесь график (waveform) представляет собой запись, состоящую из одной или нескольких пар: величина сигнала – задержка сигнала. В первой паре задержка может не указываться, подразумевается, что она нулевая.

Cпособ задержки transport означает, что при присваивании сигналы, представленные в графике, будут задержаны подобно тому, как сигнал задерживается в линии задержки или проводниках. Величина задержки отсчитывается относительно момента остановки процесса и задается выражением \выражение времени\, имеющем тип time.

Способ задержки inertial реализует поведение задержки в источнике сигнала, который не реагируют на слишком короткие входные импульсы. При этом фразой reject задается минимальная ширина импульса, которая выдается источником. Если этой фразы нет, то минимальная ширина импульса задается в фразе after. По умолчанию в операторе применяется способ задержки inertial. Действие оператора иллюстрируют следующий ряд примеров.
Y<= X after 10 ns;
- значение сигнала X на момент запуска процесса присвоится сигналу Y с задержкой 10 нс, при этом импульсы шириной менее 10 нс будут подавлены.
Y<= '0', '1' after 10 ns, '0' after 20 ns, '1' after 30 ns;
- сигналу Y сначала присвоится 0, через 10 нс – 1, через 20 нс – 0, и через 30 нс – 1, например, это задание тестовой последовательности сигнала.
Y<= А, А+В after delay_sum;
- сигналу Y сначала присвоится А, а через задержку, определяемую статическим выражением delay_sum – сумма сигналов А и В.
Y<= transport X after 1000 ns;
- модель линии задержки сигнала Х с задержкой 1 мкс.
Y<= reject t_rej inertial А and B after t_d;
- моделирует вентиль "И" с задержкой t_d , который не пропускает импульсы короче t_rej.


VHDL

Последовательные операторы

Последовательные операторы в VHDL вставляются в операторы процессов и исполняются последовательно в виртуальных процессорных элементах программистской модели, как операторы обычных алгоритмических языков. Далее рассматриваются все последовательные операторы, кроме операторов присваивания, assert и report.

Оператор ожидания события wait.

На этом операторе выполнение процесса останавливается, в момент остановки выполняются присваивания сигналам и процесс продолжает исполнение при появлении события, которое выбирается этим оператором. Синтаксис оператора wait:

\оператор wait\::=wait [on \имя сигнала\ {,\имя сигнала\}]

[until \булевское выражение\] [for \выражение времени\];

где ключевое слово on начинает список чувствительности, until - условие ожидания, а for - задержку ожидания. По оператору

wait on CLK, RST;

продолжение выполнения процесса начнется по событию изменения сигналов CLK или RST. По оператору

wait until CLK='1';

продолжение начнется в момент изменения состояния CLK из '0' в '1', т.е. по фронту этого сигнала. Оператор

wait for CLK_PERIOD;

остановит процесс на время, заданное переменной CLK_PERIOD типа time.

Возможно комбинирование списка чувствительности, условия ожидания и задержки ожидания в одномоператоре. Оператор wait без списка чувствительности, условия ожидания и задержки ожидания остановит процесс до конца моделирования.

Оператор if.

Этот условный оператор в зависимости от заданных условий выполняет цепочки последовательных операторов, причем от условия зависит, которая из цепочек операторов выполняется. Упрощенный синтаксис оператора:

\оператор if\::=if \условие 1\ then

{\последовательный оператор 1\}

[ { elsif \условие 2\ then

{\последовательный оператор 2\}]

[else

{\последовательный оператор 3\}]

end if;

Каждое из условий должно быть выражением, вычисляющим результат булевского типа. При выполнении этого оператора условия проверяются последовательно друг за другом пока результат условия не будет true. Тогда выполняется соответствующая этому условию цепочка операторов и выполнение данного оператора if прекращается.

Оператор case.

Этот оператор разрешает выполнение одной из цепочек последовательных операторов в зависимости от значения выражения селектора. Его упрощенный синтаксис:

\оператор case\::=case \простое выражение\ is

when \альтернативы\ => {\последовательный оператор\}

{when \альтернативы\ => {\последовательный оператор\}}

end case ;

\альтернативы\:= \альтернативa\{ | \альтернатива\}

В выражении селектора \простое выражение\ должен вычисляться целый результат или значение перечисляемого или регулярного типа. Это должно быть простое выражение, а не, например, конкатенация. Каждая из альтернатив \альтернатива\ должна быть такого же типа, что и \выражение\ и представлена статическим выражением или диапазоном, например, 0 to 4. Никакие два значения, получаемые из выражений альтернатив, не должны быть равны друг другу, т.е. множества альтернатив не перекрываются. Последней альтернативой может быть ключевое слово others, которое указывает на не перечисленные альтернативы. Если слово others не применяется, то в альтернативах должны быть перечислены все возможные значения, принимаемые в селекторе \выражение\.

Пример оператора case:

variable sel, a: integer 0 to 9;

………….

case sel is

when 0 => a <= 0;

when 1½2½3 => a <= 1;

when 4 to 7 => a <= 2;

when others => a <= 3;

end case;

Пустой оператор – оператор null – не выполняет никаких действий и может быть вставлен в любом месте программы как последовательный оператор. Например, если в операторе case по каким-то альтернативам не нужно ничего выполнять, то ставится этот оператор:

case sel is

when 0 => a <= 0;

when 1 to 9 => a <= b;

when others => null;

end case;

Оператор цикла.

Этот оператор несколько раз выполняет последовательность операторов. Его синтаксис:

\оператор цикла\::=[\метка\:][\схема итерации\]loop

{\последовательный оператор\}

{next[\метка\][when \условие\];}

{exit[\метка\][when \условие\];}

end loop [\метка\];

\схема итерации\::=while \условие\

| for \переменная цикла \ in \диапазон\

Метка \метка\ необязательна, она отмечает начало цикла и используется для организации вложенных циклов или для указания в каком цикле начать новую итерацию по оператору next или из какого цикла выйти по оператору exit.

По первой схеме итераций цикл, ограниченный ключевыми словами loop и end loop будет выполняться, пока условие \условие\ не примет значение false. Причем, это условие проверяется до выполнения цикла и если оно равно false, то цикл не выполняется. В примере:

variable vec: bit_vector(1 to n);

variable or_vec:bit;

variable i:natural;

…

i:=1;

or_vec:='0';

while i<=n loop

or_vec:= or_vec or vec(i);

i:=i+1;

end loop;

вычисляется переменная or_vec, равная функции ИЛИ от всех разрядов вектора vec длины n. Если n = 0, то цикл не вычисляется. Этот пример можно записать с помощью второй схемы итерации как:

variable vec: bit_vector(1 to n);

variable or_vec:bit;

….

or_vec:='0';

for i in 1 to n loop

or_vec:= or_vec or vec(i);

end loop;

Здесь переменная цикла i последовательно принимает значения 1,2,… из диапазона 1 to n. Если необходим обратный порядок изменения переменной цикла: n, n-1,… то этот диапазон может быть задан как: n downto 1 . Следует отметить, что переменную цикла не нужно объявлять, как другие переменные и ей нельзя выполнять присваивания.

Если необходимо завершить очередную итерацию до ее окончания, то применяют оператор next запуска следующей итерации. В примере

variable vec: bit_vector(1 to n);

variable numb:natural;

…

numb:=0;

for i in 1 to n loop

next when vec(i)='0';

numb:=numb+1;

end loop;

вычисляется число единиц в векторе vec.

При необходимости закончить оператор цикла до завершения всех итераций применяют оператор exit выхода из цикла. В примере

variable vec: bit_vector(1 to n);

variable numb:natural;

…

numb:=0;

for i in 1 to n loop

exit when vec(i)='1';

numb:=numb+1;

end loop;

благодаря оператору exit, находится номер самой левой единицы в векторе vec, т.е. реализована функция приоритетного шифратора.

Оператор loop часто применяется без схемы итерации, т.е. когда цикл может выполняться неопределенно большое число раз. Следующий пример илюстрирует модель счетчика синхроимпульсов clk.

signal clk: bit;

signal numb:natural;

…

numb<=0;

loop

wait until clk='1';

numb<=numb+1;

end loop;

Вызов процедуры.

Вызов процедуры также представляет собой последовательный оператор. Его упрощенный синтаксис:

\вызов процедуры\::=\имя процедуры\[([\имя параметра =>\] \выражение\

{,[\имя параметра\ => ] \выражение\})];

Здесь \имя процедуры\ - имя ранее определенной процедуры. Связывание формальных и фактических параметров выполняется аналогично как в вызове функции. Выражение - параметр функции - должно давать результат типа, соответствующего имени параметра \имя параметра\. Параметры можно задавать с поименованным или позиционным связыванием. При позиционном связывании параметры-выражения подставляются в порядке, определенном порядком следования имен параметров в определении функции. При поименованном связывании каждое имя, параметра связывается с соответствующим параметром с помощью символов "=>", причем порядок следования параметров может быть произвольным.

В пакете IEEE.Math_Real определена процедура генерации случайных чисел:

procedure UNIFORM(variable SEED1,SEED2:inout POSITIVE; variable X:out real);

Она может быть вызвана со связыванием параметров:

variable s1,s2:natural:=12345;

variable Random:real;

…

UNIFORM(X=> Random, SEED1=>s1,SEED2=>s2);

или без связывания параметров:

UNIFORM(s1,s2, Random);

Вызов процедуры без параметров – это просто написанное ее имя.

Возврат из процедуры или функции.

Оператор возврата из подпрограммы – последовательный оператор return – немедленно прерывает выполнение процедуры или вызова функции и возвращает управление в программу, вызвавшую процедуру.


VHDL

Операторы assert и report.

Эти операторы были введены в язык VHDL для выявления ошибок моделирования и сообщения о них на консоль. В методике "Hallo, World" этот оператор активно применяется. У оператора ловушки assert следующий синтаксис:

\оператор assert \::= assert \булевское выражение\

[report \строка сообщения\][severity \выражение\];

Здесь \булевское выражение\ – проверка какого–либо условия правильности моделирования, которое равно false, если найдена ошибка и true, если моделирование верно;

\строка сообщения\ - выражение типа string, представляющее строку сообщения о причине ошибки. Например, оператор

assert a(i)='0'

report "бит " & integer'image(i) &" не равен 0";

вызовет выдачу на экран дисплея сообщения:

# : ERROR : бит 1 не равен 0

# : Time: 2000 ns, Iteration: 0, TOP instance.

если a(1) ≠ 0 на 2-й микросекунде моделирования. Здесь атрибут integer'image возвращает строку, в которой представлено значение целого i в читаемом виде. Выражение \выражение\ имеет предопределенный тип severity_level, состоящий из элементов note, warning, error и failure. Значение выражения соответствует уровню критичности найденной ошибки и при самом высоком уровне failure моделирование останавливается. Например, если требуется остановить моделирование, можно записать оператор:

assert 1/=1

report "конец моделирования " severity failure;

Если не нужно ловить ошибку, а только вывести сообщение о ходе моделирования, то применяют оператор сообщения с синтаксисом:

report \строка сообщения\ [severity \выражение\];

Предыдущий пример можно переписать как:

report "конец моделирования " severity failure;

Параллельный оператор assert.

Этот оператор имеет такой же синтаксис, как и соответствующий ему последовательный оператор. Он выполняется точно так же, как и процесс, в исполнительной части которого стоит последовательный оператор assert с таким же содержанием.

Объект проекта описывается набором составных частей проекта, таких как: объявление объекта, тело архитектуры объекта. Не все знают, что в исполнительной части объекта проекта, которая открывается словом begin, вставляются параллельные операторы, которые не выполняют присваиваний сигналам, т.е. не влияют на поведение объекта. Это, так называемые, пассивные вызовы процедуры и процессы. Наиболее частое применение этих операторов – проверка соответствия входных сигналов, поступающих через порты, заданным требованиям или соответствие включения объекта в окружение, задаваемое ограничениями на настроечные константы generic. Например, проверяется время предустановки сигнала относительно фронта синхросерии, соответствие его уровней, разрядность входных данных и т.п. Так вот, при несоответствии сигналов или настроечных констант, оператор assert выдает сообщение об ошибке.

Рассмотрим пример объявления объекта RS-триггера:

entity RS_FF is

generic(delay:time);

port(R, S: in bit;

Q: out bit:='0';

nQ: out bit:='1');

begin

assert (R and S) /='1' report" In RS_FF R=S=1" severity error;

end entity RS_FF;

В нем настроечная константа delay задает параметр задержки, например, от входа до выхода, который будет подставлен при компиляции на этапе связывания компонентов. Порты R,S имеют режим ввода in, а порты Q, nQ – режим вывода out. При единичных сигналах на обоих входах, т.е. когда RS – триггер функционирует неправильно, оператор assert выдает сообщение об ошибке.


VHDL

Оператор ожидания события wait.

Этот оператор уже упоминаляся при описании вычислительной модели для программирования на VHDL, принципов работы симулятора. На этом операторе выполнение процесса останавливается, в момент остановки выполняются присваивания сигналам и процесс продолжает исполнение при появлении события, которое выбирается этим оператором. Синтаксис оператора wait:

\оператор wait\::=wait [on \имя сигнала\{,\имя сигнала\}]

[until \булевское выражение\] [for \выражение времени\];

где ключевое слово on начинает список чувствительности, until - условие ожидания, а for - задержку ожидания. По оператору

wait on CLK, RST;

продолжение выполнения процесса начнется по событию изменения сигналов CLK или RST. По оператору

wait until CLK='1';

продолжение начнется в момент изменения состояния CLK из '0' в '1', т.е. по фронту этого сигнала. Оператор

wait for CLK_PERIOD;

остановит процесс на время, заданное переменной CLK_PERIOD типа time.

Возможно комбинирование списка чувствительности, условия ожидания в одном операторе.

Оператор wait без списка чувствительности, условия ожидания и задержки ожидания остановит процесс до конца моделирования. Процесс, в котором последним оператором стоит единственный оператор wait on \СЧ\; эквивалентен процессу со списком чувствительности \СЧ\, в котором стоят те же операторы, кроме wait on . Эта эквивалентная форма процесса несколько уменьшает текст программы, улучшает его чтение и напоминает фразу allways из языкаVerilog. Программа с каким - либо оператором процесса, в котором отсутствует и список чувствительности, и оператор wait , зависает, так как такой процесс начинает вычисляться циклически без остановки и без передачи управления другим процессам.

Иногда при моделировании необходимо, чтобы процесс вначале один раз выполнил, например, процедуру ST1, а затем исполнялся периодически как обычно, допустим, выполнял процедуру ST2. Такой процесс можно запрограммировать следующим образом:

process begin

ST1;

loop

ST2;

wait on some_signal_list;

end loop;

end process;

Например, таким способом просто запрограммировать генератор синхроимпульсов:

process begin

CLK<='0';

loop

CLK<=not CLK ;

exit when end_of_simulation;

wait for 10 ns;

end loop;

wait;

end process;

Этот процесс генерирует синхросерию с периодом 10+10 наносекунд в цикле loop, выходит из него при условии end_of_simulation=true и останавливается.

Обычно симулятор VHDL работает заданный промежуток времени или без остановки. А что делать, если моделирование выполняется неопределенное время? Например, запустили тяжелое моделирование на выходные. А в понедельник пришли и нашли зависший компьютер, переполненный ненужными результатами. Тогда можно использовать такое решение.

Часто в проекте синхрогенератор - это единственный источник событий, запускающих моделирование. Каждый симулятор построен таким образом, что в случае, когда нет событий, то он останавливается с сообщением: "Simulation has finished. There are no more vectors to simulate". Следовательно, вышеописанный генератор синхросерии - удобное средство для остановки симуляции по какому - то запрограммированному условию, которое вырабатывается тогда, когда симуляция с получением ожидаемых результатов завершена.


VHDL

Последовальные логические операторы.

Последовательные логические операторы применяются только в процессах и схожи с логическими операторами других языков, например, Паскаля.

Оператор if.

Этот условный оператор в зависимости от заданных условий выполняет цепочки последовательных операторов, причем от условия зависит, которая из цепочек операторов выполняется. Упрощенный синтаксис оператора:

\оператор if\::=if \условие 1\ then

{\последовательный оператор 1\}

[ { elsif \условие 2\ then

{\последовательный оператор 2\}]

[else

{\последовательный оператор 3\}]

end if;

Каждое из условий должно быть выражением, вычисляющим результат булевского типа. При выполнении этого оператора условия проверяются последовательно друг за другом пока результат условия не будет true. Тогда выполняется соответствующая этому условию цепочка операторов и выполнение данного оператора if прекращается.

Оператор case.

Этот оператор разрешает выполнение одной из цепочек последовательных операторов в зависимости от значения выражения селектора. Его упрощенный синтаксис:

\оператор case\::=case \простое выражение\ is

when \альтернативы\ => {\последовательный оператор\}

{when \альтернативы\ => {\последовательный оператор\}}

end case ;

\альтернативы\:= \альтернативa\{ | \альтернатива\}

В выражении селектора \простое выражение\ должен вычисляться целый результат или значение перечисляемого или регулярного типа. Каждая из альтернатив \альтернатива\ должна быть такого же типа, что и \выражение\ и представлена статическим выражением или диапазоном, например, 0 to 4. Никакие два значения, получаемые из выражений альтернатив, не должны быть равны друг другу, т.е. множества альтернатив не перекрываются. Последней альтернативой может быть ключевое слово others, которое указывает на неперечисленные альтернативы. Если слово others не применяется, то в альтернативах должны быть перечислены все возможные значения, принимаемые в селекторе \выражение\.

Пример оператора case:

variable sel, a: integer 0 to 9;

………….

case sel is

when 0 => a <= 0;

when 1½2½3 => a <= 1;

when 4 to 7 => a <= 2;

when others => a <= 3;

end case;

Пустой оператор – оператор null – не выполняет никаких действий и может быть вставлен в любом месте программы как последовательный оператор. Например, если в операторе case по каким-то альтернативам не нужно ничего выполнять, то ставится этот оператор:

case sel is

when 0 => a <= 0;

when 1 to 9 => a <= b;

when others => null;

end case;


VHDL

Оператор цикла.

Этот оператор несколько раз выполняет последовательность операторов. Его синтаксис:

\оператор цикла\::=[\метка\:][\схема итерации\]loop

{\последовательный оператор\}

{next[\метка\][when \условие\];}

{exit[\метка\][when \условие\];}

end loop [\метка\];

\схема итерации\::=while \условие\ | for \переменная цикла \ in \диапазон\

Метка \метка\ необязательна, она отмечает начало цикла и используется для организации вложенных циклов или для указания в каком цикле начать новую итерацию по оператору next или из какого цикла выйти по оператору exit.

По первой схеме итераций цикл, ограниченный ключевыми словами loop и end loop будет выполняться, пока условие \условие\ не примет значение false. Причем, это условие проверяется до выполнения цикла и если оно равно false, то цикл не выполняется. В примере:

variable vec: bit_vector(1 to n);

variable or_vec:bit;

variable i:natural;

…

i:=1;

or_vec:='0';

while i<=n loop

or_vec:= or_vec or vec(i);

i:=i+1;

end loop;

вычисляется переменная or_vec, равная функции ИЛИ от всех разрядов вектора vec длины n. Если n = 0, то цикл не вычисляется. Этот пример можно записать с помощью второй схемы итерации как:

variable vec: bit_vector(1 to n);

variable or_vec:bit;

….

or_vec:='0';

for i in 1 to n loop

or_vec:= or_vec or vec(i);

end loop;

Здесь переменная цикла i последовательно принимает значения 1,2,… из диапазона 1 to n. Если необходим обратный порядок изменения переменной цикла: n, n-1,… то этот диапазон может быть задан как: n downto 1 . Следует отметить, что переменную цикла не нужно объявлять, как другие переменные и ей нельзя выполнять присваивания.

Если необходимо завершить очередную итерацию до ее окончания, то применяют оператор next запуска следующей итерации. В примере

variable vec: bit_vector(1 to n);

variable numb:natural;

…

numb:=0;

for i in 1 to n loop

next when vec(i)='0';

numb:=numb+1;

end loop;

вычисляется число единиц в векторе vec.

При необходимости закончить оператор цикла до завершения всех итераций применяют оператор exit выхода из цикла. В примере

variable vec: bit_vector(1 to n);

variable numb:natural;

…

numb:=0;

for i in 1 to n loop

exit when vec(i)='1';

numb:=numb+1;

end loop;

благодаря оператору exit, находится номер самой левой единицы в векторе vec, т.е. реализована функция приоритетного шифратора. Сравните, насколько проще оказалось программирование этой схемы по сравнению с программированием стилем потоков данных (заметка "Hallo, World"), при том, что синтезатор синтезирует этот фрагмент программы достаточно эффективно.

Оператор loop часто применяется без схемы итерации, т.е. когда цикл может выполняться неопределенно большое число раз. Следующий пример с таким циклом илюстрирует модель счетчика синхроимпульсов CLK.

signal clk: bit;

signal numb:natural;

…

numb<=0;

loop

wait until clk='1';

numb<=numb+1;

end loop;


VHDL

Процедуры и функции.

Процедуры и функции относятся к числу подпрограмм. Здесь рассмотрены правила и особенности составления и объявления процедур и функций, а также их вызова.

Спецификация процедуры.

Спецификация процедуры описывает действия при вызове процедуры и имеет следующий синтаксис:

\спецификация процедуры\::=procedure \имя процедуры\[(\список параметров\)] is

{\объявление в подпрограме\}

begin

{\последовательный оператор\}

end [procedure][\имя процедуры\];

\список параметров\::=(\элемент списка\ {; \элемент списка\})

\элемент списка\::=[constant | variable | signal ]

\идентификатор\{,\идентификатор\}: [in | out | inout] \тип параметра\

[ := \статическое выражение\]

Здесь \имя процедуры\ - идентификатор процедуры. В списке параметров указывается информация о формальных параметрах процедуры. Вместо формальных параметров подставляются фактические параметры во время вызова процедуры. В каждом из элементов списка параметров может объявляться какой это параметр (константа, переменная или сигнал) направление передачи параметра (in, out или inout) его тип или подтип и его значение по умолчанию, равное статическому выражению.

Список параметров может отсутствовать, т.е. он тогда задан неявно. При этом имена фактических параметров совпадают с именами формальных параметров, объявленых в процедуре. Обычно трудно понять программу с процедурами без списков параметров. Поэтому в соответствии с условиями повторного использования проектов, не рекомендуется программирование процедур без списка параметров.

Объявленными в процессе могут быть: объявление и тело другой процедуры или функции, объявление типа и подтипа, объявление константы, переменной, файла, псевдонима, объявление и спецификация атрибута, объявление группы, описание use.

Рассмотрим пример программирования и использования процедуры в процессе для сортировки трех целых чисел.

process(a1,a2,a3)

variable b1,b2,b3:integer;

procedure sort2(variable x1,x2:inout integer) is

variable t:integer;

begin

if x1>x2 then

return;

else

t:=x1; x1:=x2; x2:=t;

end if;

end procedure;

begin

b1:=a1; b2:=a2; b3:=a3;

sort2(b2,b3);

sort2(b1,b2);

sort2(b2,b3);

c1<=b1; c2<=b2; c3<=b3;

end process;

Здесь процедура sort2 выполняет сортировку двух переменных х1, х2, которые являются входными – выходными формальными параметрами процедуры. Вызов процедуры выполняется с позиционным связыванием.

Оператор return досрочно прерывает исполнение процедуры. Последовательный оператор return -оператор возврата из подпрограммы – немедленно прерывает выполнение процедуры или вызова функции и возвращает управление в программу, вызвавшую процедуру.

Спецификация функции.

Спецификация функции имеет следующий синтаксис:

\спецификация функции\::=[pure | impure] function \имя функции\ |\знак функции\

[(\список параметров\)] return \тип параметра\ is

{\объявление в подпрограме\}

begin

{\последовательный оператор\}

return \выражение\;

end [function][\имя функции\];

В ней знак функции – символ в кавычках, например, "+", список параметров – такой же, как в процедуре за исключением того, что режимы параметров out и inout не допускаются. После ключевого слова return в объявлении функции указывается тип возвращаемого параметра. Объявления в функции могут быть такими же, как в процедуре. Выполнение функции должно оканчиваться оператором return, вычисляющим выражение возвращаемого параметра.

Объявление процедур и функций.

Объявление подпрограмм вставляется в части объявлений в процессов, блоков, объявлениях объектов и пакетов, если эти подпрограммы используются в этих программных единицах. Оно представляет собой часть спецификации процедуры и функции до слова is :

\объявление процедуры\::= procedure \имя процедуры\[(\список параметров\)];

\объявление функции\::=[pure | impure] function \имя функции\ |\знак функции\

[(\список параметров\)] return \тип параметра\;

Вызов процедуры.

Вызов процедуры представляет собой последовательный или параллельный оператор, в зависимости от того, стоит ли он внутри или снаружи процесса. Упрощенный синтаксис последовательного вызова процедуры:

\вызов процедуры\::=\имя процедуры\[([\имя параметра =>\] \выражение\

{,[\имя параметра\ => ] \выражение\})];

Здесь \имя процедуры\ - имя ранее определенной процедуры. Связывание формальных и фактических параметров выполняется аналогично как в вызове функции. Выражение - параметр функции - должно давать результат типа, соответствующего имени параметра \имя параметра\. Параметры можно задавать с поименованным или позиционным связыванием. При позиционном связывании параметры-выражения подставляются в порядке, определенном порядком следования имен параметров в определении функции. При поименованном связывании каждое имя, параметра связывается с соответствующим параметром с помощью символов "=>", причем порядок следования параметров может быть произвольным.

В пакете IEEE.Math_Real определена процедура генерации случайных чисел:

procedure UNIFORM(variable SEED1,SEED2:inout POSITIVE; variable X:out real);

Она может быть вызвана со связыванием параметров:

variable s1,s2:natural:=12345;

variable Random:real;

…

UNIFORM(X=> Random, SEED1=>s1,SEED2=>s2);

или без связывания параметров:

UNIFORM(s1,s2, Random);

Следующий пример представляет использование процедуры со связыванием не всех формальных параметров.

procedure and4(variable x1,x2,x3,x4:in bit :='1'; signal y:out bit) is

begin

y<=x1 and x2 and x3 and x4;

end procedure;

При вызове этой процедуры:

and4(a1,a2,a3, open, b);

четвертый входной параметр отсутствует, на что указывает ключевое слово open и вместо него подставляется начальное значение '1'.

Вызов процедуры без параметров – это просто написанное ее имя.

При вызове процедуры входные параметры переменных копируются внутрь процедуры. После исполнения процедуры выходные параметры записываются на место соответствующих переменных.

Входные параметры сигналов представляются как ссылки на сигналы. Параметру сигнала нельзя присваивать начальное значение, так как источник этого сигнала недоступен. Поэтому нельзя также использовать такие атрибуты сигнала, как 'delayed, 'stable, 'quiet или 'transaction. Выходной параметр сигнала передается в процедуру вместе с источником сигнала, в котором происходит присваивание сигналу. Это эквивалентно тому, что цепочка последовательных операторов тела процедуры копируется в процесс на место вызова процедуры с соответствующей подстановкой параметров. В отличие от вызова процедуры в обычных алгоритмических языках, в которых используется одно тело процедуры, в VHDL каждый вычислительный процесс, вызывающий процедуру, использует свой собственный экземпляр тела процедуры.

Параллельный вызов процедуры имеет такой же синтаксис, как у последовательного вызова процедуры. Он исполняется точно так же, как процесс, который имеет в своей исполнительной части такой же вызов процедуры с такими же параметрами и оператор wait ожидания прихода сигналов - входных параметров. Поэтому каждый параллельный вызов процедуры соответствует некоторому виртуальному процессорному элементу, исполняющему алгоритм этой процедуры.

Если программа предназначена для синтеза, то процедура, вызываемая параллельно, не должна иметь операторов wait. Такая процедура отображается в комбинационную схему или комбинацию шин, т.е. некоторый специализированный процессорный элемент.

Вызов функции.

При вызове функции выполняется функция с заданными значениями параметров. Упрощенный синтасис вызова функции:

\вызов функции\::=\имя функции\ ([\имя параметра\ =>] \выражение\

{,[\имя параметра\ => ] \выражение\});

где \имя функции\ - имя функции, определяемой ранее, \имя параметра\ - не обязательный формальный параметр этой функции. Выражение-параметр функции - должно давать результат типа, соответствующий имени параметра. Параметры можно задавать с поименованным или позиционированным связыванием. При позиционированном связывании параметры-выражения подставляются в порядке, определенном порядком следования имен параметров в определении функции. При поименованном связывании каждое имя, параметра связывается с соответствующим параметром с помощью символов "=>", причем порядок следования параметров может быть произвольным.

В отличие от процедуры, вызов функции возвращает только один параметр, зато он может участвовать как операнд в выражениях. В языке VHDL очень мало встроенных функций. Большинство функций реализовано в виде подпрограмм. Для преобразования типов чаще всего используются функции. Например, функция

function BIT_TO_INT(x:bit_vector) return natural is

variable t, j:integer:=0;

begin

for I in x'reverse_range loop

if ( x(I)='1') then

t:=t + 2**j;

end if;

j:=j+1;

end loop;

return t;

end function BIT_TO_INT;

преобразует вектор битов в целое. При этом атрибут x'reverse_range возвращает диапазон, обратный диапазону представления входного параметра. Например, если входной параметр – bit_vector(7 downto 0), то в оператор цикла подставится диапазон 0 to 7. Таким образом, получается функция, универсальная для множества различных параметров – операндов.

Ключевые слова pure и impure обозначают идеальную и неидеальную функции. В отличие от идеальной функции, неидеальная функция может возвращать различные результаты для одинаковых наборов входных параметров. Например, если входной параметр – глобальная переменная, то она может измениться в момент вызова функции и результат будет отличаться от ожидаемого. Поэтому глобальные переменные не могут быть операндами в идеальных функциях. Примером неидеальной функции является функция Now из пакета STANDARD, которая при вызове возвращает переменную предопределенного типа delay_length, равную текущему моменту времени моделирования. Естественно, что при различных вызовах этой функции она возвращает различные значения.

Перезагрузка процедур и функций.

В языке VHDL допускается определять несколько процедур и функций с одинаковыми названиями. При вызове функции или процедуры из числа функций или процедур с одинаковым названием выбирается такая, которая подходит по типам и числу входных и выходных параметров. Такая функция перезагружает (overloads) остальные функции. Перезагрузка процедур и функций удобна при вычислениях с различными типами. Например, над типами integer, real, подтипами signed, unsigned определены одни и те же арифметические функции, но имеющие различное сочетание типов аргументов и результатов.

Примером перезагрузки служит следующая функция, которая не входит ни в один стандартный пакет:

function "and"(x1,x2:bit) return boolean is

begin

return (x1 and x2) ='1';

end;

Если эта функция объявлена, то теперь транслятор не выдаст сообщения об ошибке при выполнении оператора if, вызывающего эту функцию:

variable a,b,c: bit;

…

if (a and b and c) then

…

end if;

так как выражение в скобках будет иметь правильный тип boolean.


VHDL

Оператор процесса.

Оператор процесса – это параллельный оператор, представляющий основу языка VHDL. Его упрощенный синтаксис:

\оператор процесса\ ::=[postponed] process [(\имя сигнала\ {,\имя сигнала\})] [is]

{\объявление в процессе\}

begin

{\последовательный оператор\}

end process;

Объявленными в процессе могут быть: объявление и тело подпрограммы, объявление типа и подтипа, объявление константы, переменной, файла, псевдонима, объявление и спецификация атрибута, объявление группы, описание use. То, что объявлено в процессе, имеет область действия (видимость), ограниченную данным процессом.

Все процессы в программе выполняются параллельно. Процессы обмениваются сигналами, которые выполняют синхронизацию процессов и переносят значения между ними. Если над сигналами определена функция разрешения, то выходы источников сигнала могут объединяться. Сигналы нельзя объявлять в процессах. Процесс невозможно поместить в процесс, так как там есть место только для последовательных операторов.

В круглых скобках заголовка процесса указывается множество сигналов, по которым процесс запускается – список чувствительности. Это форма оператора процесса, альтернативная процессу с оператором wait on, стоящим последним в цепочке последовательных операторов тела процесса. Любой процесс со списком чувствительности может быть преобразован в эквивалентный процесс с оператором wait on, стоящим последним в списке последовательных операторов. В операторе процесса со списком чувствительности ставить операторы wait не допускается.

Об отложенных процессах, отмеченных ключевым словом postponed, уже говорилось, когда шла речь об архитектуре симулятора VHDL. Здесь следует добавить, что, так как отложенный процесс запускается последним в цепочке процессов с дельта-задержкой, то он сам должен исполняться с ненулевой задержкой, т.е. в нем должен быть оператор wait for.

Процесс представляет собой маленькую программу, которая выполняется на виртуальном процессорном элементе. Рассмотрим процесс, вычисляющий функцию синуса y от аргумента x по аппроксимирующей формуле:

sin(x) = c1x+c2x3+c3x5+c4x7.

Процесс выглядит следующим образом:

process

type tabl is array(0 to 3) of real;

constant c:tabl:=(0.99999, -0.16666, 0.00831, -0.00019);

variable xtmp, p: real:=0.0;

begin

xtmp:=x;

p:=c(0)*xtmp;

for i in 1 to 3 loop

p:=p+c(i)*xtmp*x*x;

end loop;

y<=p;

wait on x;

end process;

При моделировании логических схем в список чувствительности процесса необходимо вносить все входные сигналы, иначе моделирование схемы будет отличаться от ожидаемого. Например, процесс

process(A) begin

c<= A or B;

end process;

при моделировании дает графики как на рис. Из графиков видно, что изменение результирующего сигнала С происходит только в моменты изменения сигнала A, т.е. процесс моделирует некоторую триггерную схему, а не схему ИЛИ.

Если в процессе запрограммирован алгоритм функционирования триггерной схемы, например, регистра, то допускается в списке чувствительности оставлять только сигналы управления записью и разрешения чтения, например, сигналы сброса и синхросерии.

При синтезе списки чувствительности игнорируются компилятором.


VHDL

Структура программы на VHDL.

Дискретная система может быть представлена в VHDL как объект проекта. Объект – это основная составная часть проекта. Объект может быть использован в другом проекте, который, в свою очередь, описан как объект или может являться объектом более высокого уровня в данном проекте. Не путать объект проекта с объектами языка.

Объект проекта описывается набором составных частей проекта, таких как: объявление объекта называемое entity, тело архитектуры объекта (или просто архитектура), именуемое architecture, объявление пакета (package), тело пакета (package body) и объявление конфигурации (configuration). Каждая из составных частей объекта может быть скомпилирована отдельно. Составные части проекта сохраняются в одном или нескольких текстовых файлах с расширением .VHD. В одном файле может сохраняться несколько объектов проекта.

Объект проекта обычно описывается соглано синтаксису:

\объект проекта\::= [\описание library\]

[\описание use\]

\объявление объекта\

\тело архитектуры\

[\объявление конфигурации\]

[\описание library\]::= library \идентификатор\ {, \идентификатор\};

где идентификаторы – названия библиотек, которые используются в объекте проекта. Они указывают транслятору местоположение этих библиотек. Описание use указывает, какие пакеты и какие элементы этих пакетов могут быть использованы в объекте. Далее - более подробно об этом описании.

Описание use.

Объекты языка, объявленные в подпрограмме, процессе, пакете и объекте проекта видимы только в границах этих структурных единиц программы. Для того, чтобы в данной структурной единице был видимый объект, объявленный в другом месте, используется описание use. Его синтаксис:

\описание use\::= use \селективное имя\ {, \селективное имя\ };

\селективное имя\::= \имя1\. \имя2\

\имя2\::= \идентификатор\ | \символьный литерал\ |all

Здесь \имя1\ представляет собой обозначение места, где находится объект, который должен быть видимым. Это идентификатор библиотеки и идентификатор пакета в ней, разделенные точкой. Идентификатор – название объекта, который должен быть видимым, символьный литерал – символьное имя функции, например, "*". Ключевое слово all означает, что видимы все бъекты, объявленные в указанном месте. Например, чтобы были видимы функции сложения и вычитания из пакета std_logic_arith библиотеки IEEE используют

use IEEE.std_logic_arith."-", IEEE.std_logic_arith."+" ;

а если все объявления из этого пакета должны быть видимыми то используют

use IEEE.std_logic_arith.all;


VHDL

Объявление объекта.

Объявление объекта указывает, как объект проекта выглядит снаружи и каким образом его можно включить в другом объекте в качестве компонента, т.е. он описывает внешний интерфейс объекта. Синтаксис объявления объекта:

\объявление объекта\::= entity \идентификатор\ is

[generic(\объявление настроечной константы\

{; \объявление настроечной константы\});]

[port (\объявление порта\ {;\объявление порта\});]

{\объявление в объекте\}

[begin

{\оператор assert\ | \пассивный вызов процедуры\ | \пассивный процесс\ }]

end [entity][\идентификатор\];

Здесь \идентификатор\ - имя объекта. Синтаксис объявления настроечной константы и объявления порта рассмотрены в разделе описания объектов и типов языка.

Порт.

Порт представляет собой интерфейсный сигнал объекта проекта. Как и в декларации сигнала, в декларации порта указывается его идентификатор, тип, начальное значение. Дополнительно указывается режим работы: in - прием, out - передача, inout - прием и передача, buffer - передача и использование как сигнал-операнд внутри объекта проекта и link – двунаправленное соединение с другим портом с таким же режимом. Сразу укажем, что режим link - анахронизм, введенный на заре VHDL с целью дать возможность моделировать аналоговые схемы. Сейчас аналоговый VHDL для описания схем использует другие средства. Упрощенный синтаксис объявления портов объекта проекта следующий:

\объявление портов объекта\::=port (\объявление порта\

{; \объявление порта\});

\объявление порта\::=\идентификатор\: in |out|inout|buffer|link \тип\

[:=\начальное значение\] .

Настроечная константа generic.

Настроечная константа generic кодирует определенное свойство объекта проекта. Она используется, например, для задания разрядности линий связи, кодирования структуры моделируемого устройства. Упрощенный синтаксис объявления настроечных констант следующий:

\объявление настроечных констант\::=

generic(\объявление настроечной константы\

{; \объявление настроечной константы\});

\объявление настроечной константы\::=

\идентификатор\:\тип\[:=\начальное значение\]

Начальное значение порта или настроечной константы.

Начальное значение объекта в его объявлении - это то значение которое принимает объект перед первым циклом моделирования. Если начальное значение не присвоено, то симулятор присваивает наименьшее значение данного типа, если тип - числовой или самое левое значение, если тип - перечисляемый. Например, если тип STD_LOGIC, то начальное значение будет U - неинициализировано. Если при моделировании не предусматривается подача сигналов на порт такого типа, то этот порт лучше инициализировать, например, значением '0'.

Начальное значение может быть выражением. Но значение выражения должно быть вычисленным до момента трансляции данного объявления. Например, первое объявление порта:

port( bb:bit:=aa;

aa:bit :='1');

неверно, так как при его рассмотрении компилятор еще не имеет сведений об идентификаторе аа.

В аппаратной модели начальное значение порта эквивалентно состоянию шины сразу после включения питания до прихода сигналов сброса, т.е. оно не определено. Поэтому компиляторы – синтезаторы не допускают или игнорируют начальные значения всех объектов, кроме констант или объектов, которые не изменяют свое значение при вычислениях. Настроечные константы generic кодируют определенные свойства объекта проекта, например, разрядность линий связи, параметры задержки, кодирование структуры моделируемого устройства и их начальные значения принимаются во внимание.

Объявления в объекте.

Объявленными в объекте могут быть: объявление и тело процедуры или функции, объявление типа и подтипа, объявление глобальной переменной, файла, псевдонима, константы, объявление и спецификация атрибута, объявление группы, описание use.

Исполнительная часть.

В исполнительной части, которая открывается словом begin, вставляются параллельные операторы, которые не выполняют присваиваний сигналам, т.е. не влияют на поведение объекта. Поэтому такие вызовы процедуры и процессы называются пассивными. Наиболее частое применение этих операторов – проверка соответствия входных сигналов, поступающих через порты, заданным требованиям или соответствие включения объекта в окружение, задаваемое ограничениями на настроечные константы generic. Например, проверяется время предустановки сигнала относительно фронта синхросерии, соответствие его уровней, разрядность входных данных и т.п. При несоответствии сигналов или настроечных констант, оператор assert выдает сообщение об ошибке.

Рассмотрим пример объявления объекта RS-триггера:

entity RS_FF is

generic(delay:time);

port(R, S: in bit;

Q: out bit:='0';

nQ: out bit:='1');

begin

assert (R and S) /='1' report" In RS_FF R=S=1" severity error;

end entity RS_FF;

В нем настроечная константа delay задает параметр задержки, например, от входа до выхода, который будет подставлен при компиляции на этапе связывания компонентов. Порты R,S имеют режим ввода in, а порты Q, nQ – режим вывода out. При единичных сигналах на обоих входах, т.е. когда RS – триггер функционирует неправильно, оператор assert выдает сообщение об ошибке.


VHDL

Архитектура объекта.

Архитектура объекта представляет собой отдельную часть, в которой описано, каким образом реализован объект. Ее синтаксис:

\тело архитектуры\::= architecture \идентификатор\ of \имя объекта\ is

{\объявление в блоке\}

begin

{ \параллельный оператор\}

end [architecture][\идентификатор\];

Идентификатором обозначается имя конкретного тела архитектуры, а имя объекта указывает, который из объектов описан в этом теле. Одному объекту проекта может соответствовать несколько архитектур, в каждой из которых описан один из вариантов реализации объекта.

Объявление в теле архитектуры такое же, как в блоке и им может быть: объявление и тело процедуры или функции, объявление типа и подтипа, объявление файла, псевдонима, константы, глобальной переменной, объявление и спецификация атрибута, объявление группы, описание use, а также объявление компонентов. Объявленные в теле архтектуры типы, сигналы, подпрограммы видимы только в пределах этой архитектуры.

Исполнительную часть архитектуры составляют параллельные операторы, такие как процесс, блок, параллельное присваивание сигналу и др. Эти операторы исполняются параллельно.

Так как все операторы в исполнительной части тела архитектуры – параллельные, их взаимный порядок – безразличен. Хорошим стилем считается, когда параллельные операторы ставятся в последовательности, соответствующей цепочкам вершин граф-схемы алгоритма, реализуемого в архитектуре.

Примером тела архитектуры служит архитектура для объявления объекта RS – триггера:

entity RS_FF is --объявление объекта

generic(delay:time);

port(R, S: in bit;

Q: out bit:='0';

nQ: out bit:='1');

begin

assert (R and S) /='1' report" In RS_FF R=S=1" severity error;

end entity RS_FF;

architecture BEHAV of RS_FF is --описание архитектуры объекта

begin

process(S,R)

variable qi: bit;

begin

if S='1' then

qi:='1' ;

elsif R='1' then

qi:='0';

end if;

Q<=qi after delay;

nQ<=not qi after delay;

end process;

end architecture BEHAV;

Данную программу, включающую объявление объекта и тело архитектуры можно транслировать и моделировать. Если из объявления объекта удалить исполнительную часть и описание generic, то программа будет написана синтезируемым стилем и ее можно также компилировать в логическую схему.


VHDL

Пакеты.

В пакет объединяются декларации различных объектов и типов языка, связанных общим признаком. Затем декларации из пакета можно повторно использовать в различных частях проектов, ссылаясь на этот пакет. Многие пакеты стандартизированы и их использование упрощает разработку новых проектов, а также служит для стандартизации включения и тестирования этих проектов. Несколько пакетов, подчиненных одной сущности, собирают в библиотеку library. Библиотека, в которой собраны программы и пакеты пользователя, по умолчанию имеет название WORK.

Начинающий программист обычно обходится без составления новых пакетов. Но с какого-то момента развития творческих умений возникает желание оформлять проекты более компактно и более понятно, чтоб был явно виден свой авторский стиль. Тогда и возникает желание составлять свои собственные пакеты. Также без разработки пакетов не обходится создание крупных проектов, в которых участвуют несколько прграммистов и которые имеют широкое и длительное развитие.

В данной заметке показано, как разрабатываются пакеты. Пакет состоит из объявления пакета и необязательно, из тела пакета.

Объявление пакета.

Синтаксис объявления пакета:

\объявление пакета\::= package \идентификатор\ is

{объявление в пакете}

end [package][\идентификатор\];

В объявлении пакета могут быть объявленными объявление процедуры или функции, объявление типа и подтипа, объявление файла, псевдонима, константы, глобальной переменной, объявление и спецификация атрибута, объявление компонента, объявление группы, описание use.

Обычно в объявлении пакета объявляются типы, используемые во всех объектах проекта или ряда проектов. Если объявлены процедуры и функции, то их спецификации описываются в теле пакета. Т.е. объявление пакета представляет собой интерфейс пакета, также как объявление объекта – это интерфейс объекта проекта.

Константам может быть не присвоено значение. Такие константы называются отложенными (deferred). Например, это могут быть заранее неопределенная кодировка состояний или разрядность шин. Тогда эти константы должны получить значение в теле пакета.

При обращении к объектам различных библиотек с одинаковым именем необходимо использовать селективное имя объекта, указывающее, какой библиотеке оно принадлежит, например,

signal my_bit: IEEE.std_logic_1164.X01Z;

Тело пакета.

Тело пакета необходимо приводить в паре с объявлением пакета, если в последнем объявлены подпрограммы или отложенные константы. Оно имеет синтаксис:

\объявление пакета\::= package body \идентификатор\ is

{объявление в теле пакета}

end [package body][\идентификатор\];

В объявлениях тела пакета должны быть приведены полные спецификации процедур и функций, присваивания константам, которые задекларированы в объявлении этого пакета.

Ниже приведен пример пакета функций и констант, который удобно применять для сокращения работы по программированию логики с булевскими типами.

package short_boolean is

constant b0:boolean:=false;

constant b1:boolean:=true;

function b(x:bit) return boolean ;

function "not"(x:bit) return boolean ;

function "and"(x1,x2:bit) return boolean ;

function "or"(x1,x2:bit) return boolean ;

end package;

package body short_boolean is

function b(x:bit) return boolean is

begin

return x ='1';

end;

function "not"(x:bit) return boolean is

begin

return x ='0';

end;

function "and"(x1,x2:bit) return boolean is

begin

return (x1 and x2) ='1';

end;

function "or"(x1,x2:bit) return boolean is

begin

return (x1 or x2) ='1';

end;

end package body;

Теперь, если данный пакет присоединить к объекту проекта с помощью описаний library и use, то подстановка констант и функций этого пакета во многих местах, например, в операторах if , when сокращает запись программы.

Пакеты пользователя, если они соответствуют синтезируемому стилю и не содержат функции разрешения конфликтов выходов источников сигнала, обычно без труда подключаются к проекту для синтеза.


VHDL

Псевдонимы.

Под псевдонимом в языках программирования понимают другое имя объекта. Псевдонимы в VHDL помогают представить программу в виде, более удобном для чтения и моделирования. Объявление псевдонима имеет синтаксис:

\объявление псевдонима\::= alias \идентификатор\ | символьный литерал\

| \символ оператора\ [:\подтип\] is \имя\ [\сигнатура\];

Наиболее часто псевдоним дают константам, переменным и сигналам. Например, псевдоним

alias \код операции\: bit_vector(7 downto 0) is \команда\(31 downto 24);

помогает обращаться с полем кода операции команды как с отдельным сигналом, не объявляя этот сигнал. При этом бит \код операции\(7) равен биту \команда\(31).

Также псевдоним можно присваивать типу. Например, если дать псевдоним

alias vect is std_logic_vector;

то можно сократить текст программы, присваивая тип vect вместо std_logic_vector, правда, за счет ухудшения ее чтения другими программистами.

Можно давать псевдоним функциям и процедурам. Например:

alias TO_V is CONV_STD_LOGIC_VECTOR [integer, integer return std_logic_vector];

где сигнатура в квадратных скобках указывает для какой из перезагружаемых функций, различаемых по набору параметров, сделать псевдоним.

Часто псевдоним дают длинным селективным именам, которые обозначают объекты, принадлежащие различным библиотекам, как например:

alias PI is IEEE.math_real.MATH_PI ;

это псевдоним константы числа пи.

Псевдонимы поддерживаются компиляторами – синтезаторами, но далеко не всеми и не в полном объеме. Не поддерживаются, например, псевдонимы процедур и функций.


VHDL

Метки в программе.

В языке VHDL любой оператор может иметь метку. Метка представляет собой идентификатор, уникальный в пределах данной программной единицы, который отделен от оператора двоеточием. Так, в синтаксисе оператора цикла указывается, что он может иметь метку, которая используется для организации вложенных циклов и работы операторов запуска следующей итерации и выхода из цикла. Такие операторы, как generate, вставки компонента, обязаны иметь метки.

Обычно программисты пренебрегают расстановкой меток. VHDL и так требует много текстового описания (в ~1,5 раза больше, чем Verilog), а тут еще и метки… Но метки - это всё-таки неплохо. Как можно более широкое применение меток обуславливается следующими причинами.

1) В операторах процесса, блока и др. встречаются объявления констант, процедур и функций, которые видимы в пределах данного оператора. Чтоб они были видимы в другом месте, можно использовать описание use, в котором как адрес объявления, указывается метка.

2) Операторы, такие как процесс, блок, могут занимать большое количество строк текста. Тогда метка, поставленная в конце оператора, совпадающая с меткой вначале, служит закрывающей скобкой, по которой программист быстро найдет границу оператора.

3) Такие операторы, как вставка компонента и блок, обязательно имеют метку. По этой метке с помощью объявления конфигурации можно подставить нужную реализацию компонента или блока, отличную от заданной в объекте проекта.

4) При моделировании симулятор работает со скомпилированной программой, в которой всем параллельным операторам поставлены метки. Если у оператора не было метки, то симулятор ставит метку по своему усмотрению, например, номер строки, где стоит оператор. По этой метке программист ищет в модели переменные и сигналы, изменяемые в операторе. Поиск переменных удобнее делать по метке, название которой по смыслу указывает на место в программе.

5) При трансляции программы в логическую схему компилятор-синтезатор каждому параллельному оператору ставит в соответствие логическую схему или библиотечный компонент с именем, соответствующим метке оператора. Если метка отсутствует, то компилятор ставит произвольное имя, например, букву с порядковым номером. Такое имя затрудняет дальнейшие отладку и тестирование проекта на уровне логической схемы и схемы после размещения и трассировки. А по уникальной и смыслосодержащей метке можно легко найти тот самый вентиль или триггер в EDIF -файле, или VHDL-модели после разводки, в которые отразился соответствующий оператор из исходной программы. По-другому это сделать значительно труднее, так как размеры указанных файлов могут достигать нескольких сотен тысяч строк.

6) Имя метки может отражать специфику и алгоритм функционирования данного оператора. Например, процесс, моделирущий регистр с аккумулятором, может обозначаться меткой RG_ACC. В этом случае другому программисту легче разобраться в программе. Поэтому вставка смыслосодержащих меток операторов это обязательное требование для проектов, предназначенных для повторного использования.

Но при сочинении смыслосодержащей метки, как и смыслосодержащих имен переменных, сигналов, объектов проекта, нельзя переусердствовать с длиной имен. Существует практика написания длинных имен в программировании на Си, которая неприменима в программировании на VHDL.

Дело в том, что если проект иерархический, то при его синтезе компилятор приводит его до одного уровня. При этом имена вентилей и линий связи строятся как объединение имен соответствующих сигналов, меток экземпляров объектов на всех уровнях проекта. В результате, в EDIF -файле, или VHDL-модели после разводки могут появиться имена длиной в сотни символов, которые не помещаются на экране целиком, не говоря уже о длине самих файлов.

Поэтому целесообразно ограничивать длину меток и других имен 10-12 символами.


VHDL

Объявление конфигурации.

После того, как проект описан в виде объекта и его архитектуры, которая включает в себя различные компоненты, эти компоненты можно заменить на другие с таким же интерфейсом, применив объявление конфигурации. Его упрощенный синтаксис:

\объявление конфигурации\::=

configuration \идентификатор\ of \имя объекта\ is

for \имя архитектуры\

{for \указатели вставки компонента\: \имя компонента\

\указатель связывания\;

end for;}

end for;

end [configuration] [\идентификатор\];

\ указатели вставки компонента \::=\метка вставки компонента\

{,\метка вставки компонента\} | others | all

\указатель связывания\::= use entity

\имя объекта\ [(\идентификатор архитектуры\)]

При разработке вычислительного устройства его обычно тестируют на различных этапах проектирования с помощью одного и того же испытательного стенда (test bench), который также описан с помощью пары объект – архитектура, например, ALU_TB(TB_ARCH). В этом случае вставленный в испытательный стенд компонент тестируемого объекта, например, ALU с меткой UUT (unit under test), имеет различное исполнение, т.е. архитектуру, например, RTL. Для того, чтобы не изменять описание архитектуры испытательного стенда, изменяют только его конфигурацию, например:

configuration TESTBENCH_FOR_ALU of ALU_TB is

for TB_ARCH

for UUT: ALU

use entity work.ALU(RTL);

end for;

end for;

end TESTBENCH_FOR_ALU;

Расширенный синтаксис объявления конфигурации предполагает такие возможности, как подключение других конфигураций, вставку компонента непосредственно в конфигурации (в указателе связывания), связывание настроечных констант компонента с новыми значениями, отключение компонента от схемы (отложенное включение, когда в указателе связывания – ключевые слова use open).

Если в конфигурации используются компоненты, описанные в другой библиотеке, то их делают видимыми с помощью описаний library и use , которые ставят перед конфигурацией.

Конфигурации обычно игнорируются компиляторами – синтезаторами.


VHDL

Параллельные операторы.

VHDL – это язык параллельного программирования. Параллелизм в программе задается явным образом в параллельных операторах. Параллельным операторам соответствуют виртуальные процессорные элементы в программистской модели вычислителя VHDL. Параллельные операторы образуют исполнительную часть тела архитектуры. Оператор процесса - это основной параллельный оператор. Оператор вставки компонента - также важный оператор, наиболее встречаемый в проектах. В этом разделе рассмотрены эти и другие параллельные операторы.

Все параллельные операторы, кроме оператора блока и вставки компонента, могут быть заменены на эквивалентные операторы процесса, в которых список чувствительности содержит все входные сигналы выражений исходного оператора и у которых оператор wait стоит последним в цепочке последовательных операторов.

Оператор параллельного присваивания.

Этот оператор имеет такой же синтаксис, как и оператор присваивания сигналу в процессе. Такой оператор эквивалентен оператору процесса, в котором этот оператор повторен в его исполнительной части, а последним оператором стоит оператор wait со списком чувствительности. Например, следующие два оператора эквивалентны:

ADDER:A<=B+C;

ADDER_P:process begin

A<=B+C;

wait on B,C;

end process;

Оператор условного параллельного присваивания.

Оператор условного параллельного присваивания имеет синтаксис:

\условное параллельное присваивание\::= \имя\<= [\способ задержки\]

{\график\ when \булевское выражение\ else }

\график\[when \булевское выражение\];

где определение способа задержки и графика представлено выше при описании оператора присваивания сигналу.

Любой оператор условного параллельного присваивания имеет эквивалентное представление в виде процесса, как например, оператор:

cntrl<= one when st=1 else

two when st=2 or st=3 else

three;

эквивалентен оператору

process(st,one,two,three)

begin

if st=1 then

cntrl<= one;

elsif st=2 or st=3 then

cntrl<= two;

else

cntrl<=three;

end if;

end process;

Оператор селективного параллельного присваивания.

Оператор селективного параллельного присваивания имеет синтаксис:

\селективное параллельное присваивание\::= with \выражение\ select

{\имя\<= [\способ задержки\]{\график\ when \альтернативы\,}

\график\[when others ];

где \альтернативы\ имеют то же значение, что и в операторе case. Этот оператор эквивалентен соответствующему процессу, как например, оператор:

with st select

cntrl<= one when 1,

two when 2 to 3,

three when others;

выполняет такие же действия, что и процесс:

process(st,one,two,three)

begin

case st is

when 1 => cntrl<= one;

when 2 to 3 => cntrl<= two;

when others => cntrl<= three;

end case;

end process;

Требования к выражению селектора и альтернативам оператора такие же, как у оператора case. Так, каждая из альтернатив должна быть такого же типа, что и \выражение\ и представлена статическим выражением или диапазоном. Никакие два значения, получаемые из выражений альтернатив, не должны быть равны друг другу.

Параллельный оператор assert.

Этот оператор имеет такой же синтаксис, как и соответствующий ему последовательный оператор. Он выполняется точно также, как и процесс, в исполнительной части которого стоит последовательный оператор assert с таким же содержанием.

Параллельный вызов процедуры.

Параллельный вызов процедуры имеет такой же синтаксис, как у последовательного вызова процедуры. Он исполняется точно так же, как процесс, который имеет в своей исполнительной части такой же вызов процедуры с такими же параметрами и оператор wait ожидания прихода сигналов - входных параметров. Поэтому каждый параллельный вызов процедуры соответствует некоторому виртуальному процессорному элементу, исполняющему алгоритм этой процедуры.

Если программа предназначена для синтеза, то процедура, вызываемая параллельно, не должна иметь операторов wait. Такая процедура отображается в комбинационную схему или комбинацию шин, т.е. некоторый специализированный процессорный элемент.

Отложенные параллельные операторы.

Так как всем вышеперечисленным параллельным операторам ставится в соответствие оператор процесса, то поскольку процесс бывает отложенным, то и эти параллельные операторы могут быть отложенными. Такие операторы, как и отложенный процесс, обозначаются ключевым словом postponed, которое ставится перед оператором.


VHDL

Оператор вставки компонента.

Оператор вставки компонента - это любимый оператор начинающих программистов. Он играет основную роль для реализации иерархического проектирования. Его синтаксис:

\оператор вставки компонента\::= \метка экземпляра элемента\ :

                                 \вставляемый элемент\

                [generic map(\связывание настроечной константы\

                       {, \связывание настроечной константы\});]

                [port map (\связывание порта\

                         {,\связывание порта\})];

   \вставляемый элемент\ ::= [component] \имя компонента\

                  | entity \имя объекта\[идентификатор архитектуры]

               | configuration \имя конфигурации\

Действие этого оператора заключается в подстановке вместо себя одного экземпляра компонента (вставляемый элемент - компонент) или объекта (вставляемый элемент - объект проекта), или компонента, указанного в конфигурации. Если вставляется компонент, то он должен быть объявлен в данной архитектуре.

Сколько раз встречается имя вставляемого компонента – столько копий объекта вставляется в странслированную программу. При этом каждая копия имеет уникальное имя, указанное в метке компонента. Таким образом, при многократной вставке компонента в странслированном проекте дублируются несколько раз все параллельные операторы указанного компонента, а, следовательно, дублируются сответствующие им виртуальные процессорные элементы программистской модели.

Фраза \связывание порта\ указывает порядок подключения сигналов данного тела архитектуры к портам – сигналам компонента. Связывание может быть как позиционным, так и ассоциативным (поименованным), а также комбинированным. При позиционном связывании параметры-выражения подставляются в порядке, определенном порядком следования имен параметров в объявлении компонента. При поименованном связывании каждое имя порта связывается с соответствующим сигналом с помощью символов "=>", причем порядок следования портов может быть произвольным. Второй способ связывания предпочтителен, так как поименованное связывание более понятно при чтении и меньше вероятность допустить ошибку при записи.

Неподключенные порты с режимом out или inout допускается не указывать в списке связывания портов. Но более понятным и правильным считается связывание таких портов с условным сигналом, обозначенным ключевым словом open.

В поименованном связывании допускается связывать вырезку порта с сигналом. Например, вставка компонента регистра, выходы которого подключены к различным сигналам, имеет вид:

U_RG: RG16 port map (CLK => CLK,

                      E  => \разр_зп_рг\,

                      DI =>     D,

                      DO(15)=> open,

                      DO(14)=> \знак_D\,

                      DO(13 downto 0)=>\мантисса_D\ );

Более полный синтаксис допускает связывать порт и сигнал в виде статического выражения с использованием вызовов функций, например:

DI => Conv_Integer(D(n-1 downto 0));

  To_Bit(DO(14)) => \знак_D\,

т.е. здесь для совмещения типов порта DI в режиме in и сигнала D, разряда DO(14) порта в режиме out и сигнала \знак_D\ используются функции преобразования типа.

Следует отметить, что компиляторы – синтезаторы, как правило, не допускают связывание порта с функцией преобразования типа. Если выход компонента не подключен, как, например, DO(15)=>open или если выхода нет в списке связываний, то компилятор-синтезатор может минимизировать в компоненте цепи и логику, относящиеся к этому выходу, в примере – удалить триггер, подключенный к DO(15).

Синтаксис связывания настроечной константы аналогичен синтаксису связывания порта. При таком связывании настроечная константа, обозначающая, например, разрядность шин, объем памяти, задержку элемента, передается из объекта проекта более высокого уровня в объект более низкого уровня, который становится компонентом. Другими словами, при связывании настроечных констант выполняется настройка в некотором смысле обобщенного объекта до компонента с конкретными параметрами.

Все компиляторы – синтезаторы поддерживают настроечные константы целого типа.

Пусть на нижнем уровне иерархии описана модель синхронного регистра разрядности n, который принимает данное DI по фронту синхросигнала CLK:

entity RGn is

   generic(n: integer);

   port(CLK:bit;  DI, DO: bit_vector(n-1 downto 0));

end entity;

architecture behav of RGn is begin

   process(CLK)

   begin

       if CLK='1' and CLK'event then

             DO<=DI ;

       end process;

end architecture behav;

Тогда следующий оператор в теле архитектуры более высокого уровня иерархии выполняет вставку компонента этого регистра и настраивает его разрядность равной n = 8:

U_RG8: entity RGn(proc) generic map(8),

                         port map (CLK, DI=>DATA_IN, DO=>DATA_OUT);


VHDL

Оператор generate.

Если необходимо неоднократно повторить один или несколько параллельных операторов, то используют оператор generate. Его синтаксис:

\оператор generate\::= \метка\: for \идентификатор\ in \диапазон\ generate

                              [{\объявление в блоке\}

                          begin]

                              { \параллельный оператор\}

                          end generate [\метка\];

Метка оператора generate необходима для обозначения сгенерированной структуры, \идентификатор\ - это параметр оператора generate, а фраза \диапазон\ - диапазон его изменения. Они имеют такие же синтаксис и семантику, как и в операторе loop. В операторе могут быть вставлены такие же объявления, как в декларативной части тела архитектуры.

В отличие от оператора loop, который повторяет в цикле один или несколько последовательных операторов, оператор generate делает несколько копий параллельных операторов, когда параметр оператора пробегает все значения из заданного диапазона.

В следующем примере с помощью оператора generate запрограммирована схема сдвигового регистра длиной n на триггерах FD из библиотеки компонентов ПЛИС Xilinx, описанного в пакете UNISIM.unisim_VITAL с входом DI и выходом DO, тактируемого синхросерией CLK.

signal t: std_logic_vector(1 to n+1);

…

t(1)<=DI;

FIFO: for i in 1 to n generate

           U_ TT: FD(C=>CLK, D=>t(i), Q=>t(i+1));

      end generate;

DO<=t(n+1);

Для того чтобы управлять структурой проектируемого устройства используется условный оператор generate. Его синтаксис:

\условный оператор generate\::= \метка\: if \булевское выражение\ generate

                                [   {\объявление в блоке\}

                          begin]

                             { \параллельный оператор\}

                          end generate [\метка\];

В зависимости от условия, заданного булевским выражением, оператор вставляет или нет в структуру устройства узлы, представленные параллельными операторами. Так как это булевское выражение влияет на структуру устройства, оно должно быть статическим. В примере:

RESn: if \подключить_PULLUP\=1 generate

      RES1:for i in DATA_BUS'range generate

                   U_ RES: PULLUP(DATA_BUS(i));

           end generate;

      end generate;

если целое значение \подключить_PULLUP\ равно 1, то к шине DATA_BUS  подключаются компоненты нагрузочных резисторов PULLUP из библиотеки UNISIM.

Направлением научной деятельности автора является синтез структур вычислительных устройств. Поэтому язык VHDL нравится именно тем, что с помощью таких средств, как оператор generate можно программировать структуру устройства в зависимости от параметров ее настройки. Например, можно создать проект универсального цифрового фильтра, число ступеней которого изменяется в зависимости от заданного качества фильтрации.

К сожалению, в языке Verilog нет операторов, аналогичных generate. И только поэтому не рекомендуется в проектах для синтеза использовать этот оператор, так как такой проект трудно перевести на Verilog, если возникнет такая необходимость. В этом случае прийдется написать столько Verilog - программ, сколько вариантов настройки структуры. Или на каком-то алгоритмическом языке, например, Java, Perl, VHDL написать программу, генерирующую Verilog - файл, соответствующий заданной настройке.


VHDL

Атрибуты.

Язык VHDL предоставляет программисту широчайшие возможности для выражения того, чего он задумал. Один и тот же проект можно описать по-разному, но получить одинаковые результаты. Если характер этих различий выстраивается в некоторую систему, то говорят, что программа написана каким-то стилем.

Ниже рассматриваются основные выработанные стили программирования на VHDL.

Входным блоком любого транслятора является синтаксический анализатор (parser). Его главная функция - определить, написан ли данный текст таким-то языком, или нет (мол, есть ли ошибки и где), и если да - то предоставить грамматический разбор. Ему безразлично то, что этот текст означает и его форма написания, т.е. его семантика и стилистика. Собственно компиляция означает подстановку цепочек библиотечных компонентов вместо значимых операторов и выражений в соответствии с их семантикой. Стилистика программы VHDL различается только компиляторами-синтезаторами. И то только в том плане, что они отказываются компилировать программы, не соответствующие синтезируемому стилю. В частности, здесь устоялся характерный стиль описания регистров и блоков памяти.

Операторы процесса задают поведение сигналов в зависимости от событий, происходящих во времени. Поэтому если архитектура включает только операторы процесса, то говорят, что такая архитектура описана поведенческим стилем.

Операторы параллельного присваивания, вызова процедуры, условного и селективного параллельного присваивания указывают потоки данных между линиями связи, обозначенными идентификаторами сигналов, а также обработку этих потоков. Поэтому если в теле архитектуры встречаются только такие операторы, то говорят, что эта архитектура написана стилем потоков данных.

Наконец, в архитектуре, описанной только операторами вставки компонента, непосредственно закодирована структура проектируемого устройства. Сами операторы отвечают структурным блокам, а сигналы, связанные с портами – линиям связи между этими блоками. Поэтому говорят, что такая архитектура описана структурным стилем.

Естественно, архитектуры, описанные различными стилями, могут иметь произвольное количество операторов generate и block. Часто встречаются архитектуры, описанные смешанным стилем.

В программах, предназначенных для синтеза, регистры и другие схемы с памятью можно описать только с помощью оператора процесса или вставкой компонента с памятью. Так как в архитектуре, описанной стилем потоков данных, нет операторов процессов, то такая архитектура описывает комбинационную схему. Исключением является случай, поддерживаемый некоторыми компиляторами, когда регистр задается оператором block со сдерживаемыми операторами параллельного присваивания, выражение сдерживания которого является условием разрешения записи.

Хорошим стилем программирования считается, когда в иерархическом проекте объекты верхних уровней описываются только структурным стилем.

Стиль программирования разработчиков может отличаться в соответствии с их вкусами. Например, многие, особенно начинающие, предпочитают стиль потоков данных с применением операторов процесса только для описания регистров. Такой стиль дает прямую аналогию между программой и логической схемой. Для многих разработчиков этот стиль перекочевал из технологии программирования ПЛМ.

Автор больше склоняется к такому стилю написания программ, когда используется малое количество больших операторов процесса. При этом проект устройства представляется в воображении как параллельная система из специализированных процессорных элементов, соответствующих операторам процесса. Кроме того, так как число процессов мало, поведенческое моделирование проекта выполняется более ускоренно.

Но слишком большой и неструктурированный процесс может стать запутанным, а синтезированная по нему схема - неоптимальной (руководство по синтезатору иногда предупреждает об этом). В этом единственный недостаток такого стиля. В этом плане полезен совет из программирования на Си: - программный модуль должен быть не большим и не маленьким, а таким, чтобы помещался в поле зрения. Поэтому оптимальный по величине оператор процесса должен занимать не более 1 страницы текста.


VHDL

Оператор block.

В языке VHDL блок представляет собой выделенное множество параллельных операторов. Этот оператор, как и оператор процесса является основным операторам языка VHDL. Все операторы вставки компонента в проекте можно заменить на эквивалентные операторы блока. Большой иерархический объект проекта можно представить одним объектом, в котором компоненты заменены эквивалентными блоками. Синтаксис этого оператора:

\оператор block\::=[\метка\]: block [\выражение сдерживания\] [is]

            [generic(\объявление настроечной константы\

                   {; \объявление настроечной константы\});]

            [generic map(\связывание настроечной константы\

                      {, \связывание настроечной константы\});]

            [port (\объявление порта\ {;\объявление порта\});]

            [port map (\связывание порта\

                      {,\связывание порта\})];

                      {\объявление в блоке\}

             begin

                       {\параллельный оператор\ }

             end block [\метка\];

В описании блока фраза generic объявляет типы внутренних настроечных констант блока, фраза generic map, описывает список связывания настроечных констант, поступающих извне с внутренними настроечными константами, объявления порта описывают входные и выходные сигналы блока, а список связываний портов задает соответствие внешних сигналов и сигналов портов. В блоке могут быть объявлены те же объекты языка, которые объявляются в теле архитектуры.

Отдельное необязательное булевское выражение сдерживания неявно задает специальный необъявляемый сигнал guard, который разрешает или запрещает (сдерживает) выполнение операторов присваивания сигналу с условием guard. Этот же сигнал может участвовать как операнд в выражениях в пределах блока.

Как и в других языках программирования, блоки в VHDL выполняют две основные функции: создание локальной памяти для сигналов и введение обособленной области их действия (области видимости). Также блоки могут иметь иерархическое построение, т.е. могут применяться в блоках на более высоком уровне. С помощью оператора конфигурации можно вместо одних блоков подставлять блоки с другим исполнением. Эквивалентным блоком можно заменить любую пару объект-архитектура, используемую как компонент.

В разделах, посвященных операторам процесса и присваивания сигналу указывалось, что нельзя одному сигналу присваивать значение в разных процессах, если над типом сигнала не определена функция разрешения. Для реализации корректного присваивания сигналу любого типа в разных процессах, язык VHDL предоставляет операторы присваивания сигналу со сдерживанием.

Для этого, во-первых, процесс с оператором присваивания сигналу или соответствующий параллельный оператор помещают в блок с выражением сдерживания. Во-вторых, оператор присваивания сигналу оформляют как оператор со сдерживанием, для чего перед выражением оператора ставится ключевое слово guarded. Например, блоки В1 и В2:

signal A,B,C: out integer bus :=0;

disconnect С:integer after 2 ns;

…

4B1: block (sel = 1) is begin

       С <= guarded А;

    end block B1;

B2: block (sel = 2) is begin

       С <= guarded D;

    end block B2;

выдают в общую шину, представленную сигналом С, целое значение А при условии равенства 1 управляющего сигнала sel (т.е. когда сигнал guard<=(sel = 1) равен true) и значение сигнала D при другом условии в выражении сдерживания. Если guard = false, то источник сигнала отключается от шины, т.е. выполняется его сдерживание. Отключение источника может происходить с задержкой, устанавливаемой в объявлении disconnect, которое следует за объявлением сигнала. В приведенном примере отключение происходит с задержкой 2 нс.

В случае, когда не выбран ни один источник, сигнал принимает свое предыдущее значение, если источник сигнала типа register или предварительно заданное значение, если источник сигнала типа bus. Ключевыми словами register и bus сигналы обозначаются при их объявлении. Благодаря механизму сдерживания, один сигнал может иметь несколько источников – выходов блоков. При этом правильное поведение этого сигнала состоит в выборке не более одного источника сигнала одновременно, т.е. сигнал guard защищает (guards) общую шину от неправильного функционирования. Таким образом, еще одной основной функцией блоков в VHDL является организация нескольких источников для одного сигнала.

Обычно трансляция операторов блоков поддерживается компиляторами-синтезаторами. Но использование механизма подключения к общей шине, обеспечиваемого блоками, а также программирование поведения модели, связанное с ключевыми словами register, bus, disconnect, как правило, запрещаются. Также не поддерживаются связывания портов и настроечных констант в блоках. Следует отметить, что при внедрении проекта устройства иногда его необходимо перевести на язык Verilog, в котором отсутствует оператор, эквивалентный оператору block. Поэтому использование оператора block при синтезе не рекомендуется.


VHDL для синтеза

Однотактная синхронизация против двухтактной

В сентябре 1979 г. в лаборатории спец-ЭВМ кафедры вычислительной техники КПИ под руководством Ю.С.Каневского приступили к системной отладке самого скоростного в стране опытного образца процессора БПФ, собранного из 2000 микросхем серии К155. Отладка шла, в целом, успешно. Но процессор упорно отказывался работать стабильно. Как ни меняли конструкцию системы синхронизации, как не варьировали период и скважность синхросерии - данные нет-нет, да проскакивали лишний уровень регистров. Было принято кардинальное решение - заменить все асинхронные регистры ТМ5 на синхронные ИР1. Т.е. заменить двухтактную синхронизацию на однотактную. Второе решение - никогда больше в лаборатории Ю.С.Каневского не применять двухтактную синхронизацию… А отлаженный и испытанный процессор еще несколько лет надежно работал где-то на Дальнем Востоке.

Проектирование микросхем и в частности, систем на кристалле (СНК) характеризуется тем, что ошибка в проекте обходится слишком дорого, а ее локализация в микросхеме и выяснение ее причин очень затруднительны. Поэтому основным правилом проектирования является то, что поведение ВУ в кристалле должно быть предсказуемым.

В вычислительной технике используются, в основном, два принципа синхронизации вычислительных устройств (ВУ): двухтактной и однотактной синхронизации. Эти принципы обеспечивают различный уровень предсказуемости поведения ВУ и их необходимо рассмотреть подробнее.

В вычислительном устройстве можно выделить группы регистров и триггеров, которые образуют уровни, причем при их соответствующем тактировании информация передается от одного уровня к другому, претерпевая по пути обработку в логических схемах. При двухтактной синхронизации соседние уровни регистров и триггеров синхронизируются различными синхросигналами (рис. 1).

Благодаря двухтактной синхронизации, триггеры могут быть выполнены по простейшей электрической схеме, т.е. как асинхронные, принимающие данные по уровню синхросерии. Для правильной работы ВУ прием данных в соседних уровнях триггеров должен выполняться в разных активных фазах синхросигналов CLK1 и CLK2. При перекрытии этих фаз (пример перекрытия выделен цветом на рис. 1) возможна ситуация неправильного приема данного и даже прохождения данного через несколько уровней триггеров без запоминания. Поэтому фазы синхросерий выполняют с защитным временным промежутком между ними.

Задержки в линиях соединений могут превосходить задержки в логических схемах и триггерах. Эти задержки трудно выполнить нормированными в заданных пределах, а при реализации в ПЛИС – это почти невозможно. Поэтому принцип двухтактной синхронизации применяется только тогда, когда защитный промежуток между фазами достаточно велик. А это приводит к существенному уменьшению быстродействия ВУ по сравнению с максимально возможным.

Если в ВУ применяются RS – триггеры и другие асинхронные триггеры, например, защелки, то такое ВУ необходимо отнести к схеме с двухтактной синхронизацией. Даже если в такой схеме используется один синхросигнал, то второй синхросигнал присутствует неявно. Например, его могут получать инвертированием первого синхросигнала.

При разработке проектов для ПЛИС двухтактная синхронизация практически никогда не применяется, так как трудно получить проект с гарантированной работоспособностью. Но, например, в блоке распределенной памяти, выполненном на LUT, такая синхронизация использована: по фронту синхросигнала записываются адрес и данное в защелки, а по его спаду – данное переписывается в триггер – защелку памяти. Но LUT разрабатывался с таким расчетом, чтоб его поведение было предсказуемым при любой прошивке ПЛИС, и чтобы пользователь воспринимал эту память как синхронную. Кстати, в первых ПЛИС эта память была асинхронной и необходимо было вводить дополнительные временные ограничения на сигналы, чтобы она работала корректно.

В некоторых ВУ используется асинхронный способ вычислений на логическом уровне, благодаря чему понижается энергопотребление до минимума. Но разработка таких ВУ не поддерживается стандартными САПР и тем более - САПР для ПЛИС.

Двухтактная синхронизация относится к асинхронному управлению. Другим случаем такого управления является асинхронная начальная установка или сброс триггеров ВУ. Если сигнал сброса не согласован по времени с синхросигналом или если в схеме используются несколько сигналов сброса, то она может функционировать некорректно. Например, после сброса, состояние управляющего автомата, следующее за начальным, может быть случайным, если задержка между сигналом сброса и фронтом синхросерии слишком мала. Для избежания этого в ПЛИС организована шина глобального сброса, подводящая сигнал сброса-установки ко всем триггерам почти одновременно.

При однотактной синхронизации все триггеры ВУ выполнены как синхронные и тактируются фронтом одного синхросигнала (рис. 2). При этом условием правильности функционирования ВУ является неравенство критической задержки:

max(TTi+TDi,j + TПj ± ΔTCi,j) < TC, (1)

i,j

где TTi – задержка от фронта синхросигнала до выхода i-го триггера, TDi,j – задержка сигнала в логических схемах и линиях связи между i –м и j – м триггером, TПj – время предустановки сигнала на входе j-го триггера относительно фронта синхросигнала, ΔTCi,j - относительная задержка между синхросигналами, приходящими на эти триггеры, называемая перекосом фазы (clock skew), TC – заданный период синхросигнала, при условии, что время удержания сигнала на входе триггера ТУ удовлетворяет заданным ограничениям.

В современных микросхемах сеть передачи синхросигнала от источника до всех триггеров выполняется с особой тщательностью и она обеспечивает минимальный перекос фаз, находящийся в пределах допустимого. Благодаря этому, формула (1) упрощается до следующей формулы:

max(TTi+TDi,j + TПj ) < TC . (2)

i,j

Временной анализ проектов микросхем

Предсказание правильности поведения ВУ с однотактной синхронизацией во всех САПР микросхем основано, прежде всего, на временном анализе задержек схемы ВУ, который выполняет программа временного анализа. Эта программа по известным задержкам между всеми элементами проекта ВУ, включая задержки в проводниках, выполняет проверку условия (2). Также вычисляются задержки от входных выводов микросхемы до входов триггеров и от выходов триггеров до выходных выводов микросхем.

Задержки определяются как маршруты между вершинами графа схемы ВУ, дуги которого нагружены соответствующими задержками вентилей или проводников. Во многих ВУ используются сложные логические схемы, которые можно представить многовершинными двудольными графами с большим числом ребер. В этом случае количество маршрутов, по которым определяются задержки, представленных ребрами в двудольном графе, может достигать многих миллионов. Из-за перебора всех маршрутов временной анализ ВУ может длиться довольно долго.

Если в ВУ существует перекос фаз, то временной анализ усложняется, так как он выполняется по более сложной формуле (1). Во многих САПР автоматический учет перекоса фаз не выполняется или проводится только для отдельно выбранных маршрутов. Если ВУ состоит из нескольких связанных между собой модулей, в пределах которых действуют разные синхросерии, то дополнительно проверяется условие (1), в котором ΔTCi,j - относительная задержка между фронтами двух синхросерий, а задержки определяются по маршрутам сигналов между парами блоков.

Часто, операнд записывается в триггер i и хранится в нем несколько тактов, в течение которых сигнал операнда распространяется через логическую схему до триггера j, в который операнд записывается также через несколько тактов. Очевидно, что такой маршрут желательно удалить из временного анализа или анализировать отдельно, так как через него практически никогда не проходит критическая задержка. Такие маршруты выделяют в виде множества многотактовых маршрутов (multicycle paths), называемых также ложными маршрутами (false paths).

В результате временного анализа подтверждается, что схема ВУ работает с однотактной синхронизацией, что в ней отсутствуют критические перекосы фаз, а также фиксируются критический путь и его задержка, которые характеризуют быстродействие ВУ. Это быстродействие обычно выражается величиной минимального тактового периода TCmin, определяемого левой частью формулы (1) или максимальной тактовой частотой fmax = 1/TCmin.

Стадия размещения вентилей логической схемы по площади кристалла и трассировки межсоединений является ответственным этапом проектирования микросхемы и прошивки ПЛИС, так как от нее зависят все основные характеристики СНК. В то же время, это одна из самых трудоемких стадий. Она сводится к серии последовательных приближений к эффективному варианту размещения в плоскости микросхемы графа соединения вентилей (рис. 27).

Одним из критериев оптимизации размещения и трассировки является минимум задержки критического пути. На основе временного анализа выполняется автоматическая оптимизация быстродействия схемы ВУ путем сокращения длины найденных критических путей. Поэтому для ускорения и улучшения оптимизации желательно минимизировать количество проверяемых маршрутов, например, отмечая многоцикловые маршруты и выделяя критические маршруты, требующие оптимизации.

Конвейеризация вычислений, которая сводится к "расщеплению" сложных логических схем промежуточными конвейерными регистрами, существенно (от десятков до тысяч раз) сокращает число проверяемых маршрутов. Поэтому в конвейерных ВУ достигается прирост производительности не только благодаря укорачиванию маршрутов, но и за счет улучшения работы программы, оптимизирующей проект ВУ.

Исходя из вышеизложенных особенностей проектирования микросхем, разработчики фирм – производителей микросхем предлагают следующие рекомендации :

Þ Применять только однотактную синхронизацию и желательно, только один синхросигнал.

Þ Если в ВУ используется несколько синхросигналов, в том числе один сигнал, но со срабатыванием по фронту и спаду, то минимизировать их число, а их распространение ограничить отдельными модулями – по одному синхросигналу на модуль; синхросигналы генерировать в одном, предназначенном для этого модуле.

Þ Не допускать существенных перекосов фаз.

Þ Минимизировать количество проверяемых маршрутов, в частности, выделением множества многоцикловых маршрутов и конвейеризацией ВУ.

Þ Отделять быстродействующие блоки от медленных блоков и оптимизировать их раздельно.

Þ Обеспечить запоминание в регистрах модулей ВУ выходных сигналов, а еще лучше – и входных сигналов. Благодаря этому, не только ускоряется временной анализ, повышается максимальная тактовая частота, но и упрощается стыковка модулей между собой, упрощаются условия повторного использования модулей (вычислительных заготовок).

Þ Реализовать преимущественно синхронные начальные установку или сброс триггеров, особенно в схемах управления.

Þ При реализации в ПЛИС желательно все триггеры выполнить с асинхронным сбросом или установкой по одному сигналу.


VHDL

...

Подготавливается к публикации.


VHDL содержание

VHDL

СОДЕРЖАНИЕ

  1. Вступление

  2. Изучение VHDL. Методика "Hallo, Word!"

  3. Изучение VHDL.Что такое VHDL.

  4. VHDL - FPGA. Технология разработки систем на кристалле.

  5. Изучение VHDL.Программистская модель вычислителя VHDL.

  6. Ещё один тахометр

  7. Изучение VHDL. Как работает симулятор.

  8. Стиль программирования для синтеза

  9. VHDL - FPGA. Что такое FPGA?

  10. Литералы

  11. Типы

  12. Oбъекты языка VHDL

  13. Операции в выражениях

  14. Операнды в выражениях

  15. Реализация выражения в аппаратной модели VHDL.

  16. Статические выражения

  17. Последовательный оператор присваивания

  18. Последовательные операторы

  19. Операторы assert и report

  20. Оператор ожидания события wait

  21. Последовальные логические операторы

  22. Оператор цикла

  23. Процедуры и функции

  24. Оператор процесса

  25. Атрибуты

  26. Структура программы на VHDL (new)

  27. Объявление объекта (new)

  28. Архитектура объекта (new)

  29. Пакеты (new)

  30. Псевдонимы (new)

  31. Метки в программе (new)

  32. Объявление конфигурации (new)

  33. Параллельные операторы (new)

  34. Оператор вставки компонента (new)

  35. Оператор generate (new)

  36. Атрибуты (new)

  37. Оператор block (new)

  38. VHDL для синтеза (new)
Назад Содержание На главную Далее